]> git.saurik.com Git - apple/security.git/blobdiff - SecurityTests/cspxutils/badattr/badattr.c
Security-57031.1.35.tar.gz
[apple/security.git] / SecurityTests / cspxutils / badattr / badattr.c
diff --git a/SecurityTests/cspxutils/badattr/badattr.c b/SecurityTests/cspxutils/badattr/badattr.c
new file mode 100644 (file)
index 0000000..18708b8
--- /dev/null
@@ -0,0 +1,1417 @@
+/*
+ * badattr.c - verify proper rejection of bad key attribute bits
+ */
+#ifdef pcode
+
+partial description...
+
+for each asymmetric alg {
+       gen pub key with KEYUSE_ENCRYPT
+               make sure you cannot use it for vfy or decrypt
+               make sure you cannot use it for encrypting with other alg
+       gen priv key with KEYUSE_DECRYPT
+               make sure you cannot use it for sign or decrypt
+               make sure you cannot use it for decrypting with other alg
+       gen priv key with KEYUSE_SIGN
+               make sure you cannot use it for encrypt or decrypt
+       gen pub with KEYUSE_VERIFY 
+               make sure you cannot use it for encrypt or decrypt
+
+}
+
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <Security/cssm.h>
+#include <Security/cssmapple.h>
+#include "cspwrap.h"
+#include "common.h"
+#include "cspdlTesting.h"
+/*
+ * Enumerate algs our own way to allow iteration.
+ */
+typedef unsigned privAlg;
+enum {
+       ALG_ASC = 1,
+       ALG_DES,
+       ALG_RC2,
+       ALG_RC4,
+       ALG_RC5,
+       ALG_3DES,
+       ALG_AES,
+       ALG_RSA,
+       ALG_FEE,
+       ALG_ECDSA,
+       ALG_DSA
+};
+
+#define SYM_FIRST              ALG_ASC
+#define SYM_LAST               ALG_AES
+#define ASYM_FIRST             ALG_RSA
+#define ASYM_LAST              ALG_ECDSA               /* DSA if we're patient */
+
+/*
+ * ops expressed at bitfields
+ */
+#define OP_SIGN                0x0001
+#define OP_VERIFY      0x0002
+#define OP_ENCRYPT     0x0004
+#define OP_DECRYPT     0x0008
+#define OP_GENMAC      0x0010
+#define OP_VFYMAC      0x0020
+
+static void usage(char **argv)
+{
+       printf("usage: %s [options]\n", argv[0]);
+       printf("   Options:\n");
+       printf("   s(ymmetric only)\n");
+       printf("   a(symmetric only)\n");
+       printf("   q(uiet)\n");
+       printf("   h(elp)\n");
+       exit(1);
+}
+
+/*
+ * Common, flexible, error-tolerant symmetric key generator.
+ */
+static int genSymKey(
+       CSSM_CSP_HANDLE         cspHand,
+       CSSM_KEY_PTR            symKey,
+       uint32                          alg,
+       const char                      *keyAlgStr,
+       uint32                          keySizeInBits,
+       CSSM_KEYATTR_FLAGS      keyAttr,
+       CSSM_KEYUSE                     keyUsage,
+       CSSM_RETURN                     expectRtn,
+       CSSM_BOOL                       quiet,
+       CSSM_BOOL                       freeKey,                        // true: free the key on exit
+       const char                      *testStr)
+{
+       CSSM_RETURN                     crtn;
+       CSSM_CC_HANDLE          ccHand;
+       CSSM_DATA                       dummyLabel = {4, (uint8 *)"foo"};
+       int                                     irtn;
+       
+       memset(symKey, 0, sizeof(CSSM_KEY));
+       crtn = CSSM_CSP_CreateKeyGenContext(cspHand,
+               alg,
+               keySizeInBits,  // keySizeInBits
+               NULL,                   // Seed
+               NULL,                   // Salt
+               NULL,                   // StartDate
+               NULL,                   // EndDate
+               NULL,                   // Params
+               &ccHand);
+       if(crtn) {
+               printError("CSSM_CSP_CreateKeyGenContext", crtn);
+               return testError(quiet);
+       }
+       crtn = CSSM_GenerateKey(ccHand,
+               keyUsage,
+               keyAttr,
+               &dummyLabel,
+               NULL,                   // ACL
+               symKey);
+       if(crtn != expectRtn) {
+               printf("***Testing %s for alg %s:\n", testStr, keyAlgStr);
+               printf("   CSSM_GenerateKey: expect %s\n",      cssmErrToStr(expectRtn));
+               printf("   CSSM_GenerateKey: got    %s\n",  cssmErrToStr(crtn));
+               irtn = testError(quiet);
+       }
+       else {
+               irtn = 0;
+       }
+       CSSM_DeleteContext(ccHand);
+       if(freeKey && (crtn == CSSM_OK)) {
+               cspFreeKey(cspHand, symKey);
+       }
+       return irtn;
+}
+
+/*
+ * Common, flexible, error-tolerant key pair generator.
+ */
+static int genKeyPair(
+       CSSM_CSP_HANDLE         cspHand,
+       uint32                          algorithm,
+       const char                      *keyAlgStr,
+       uint32                          keySizeInBits,
+       CSSM_KEY_PTR            pubKey,                 
+       CSSM_KEYATTR_FLAGS      pubKeyAttr,
+       CSSM_KEYUSE             pubKeyUsage,    
+       CSSM_KEY_PTR            privKey,                
+       CSSM_KEYATTR_FLAGS      privKeyAttr,
+       CSSM_KEYUSE             privKeyUsage,   
+       CSSM_RETURN                     expectRtn,
+       CSSM_BOOL                       quiet,
+       CSSM_BOOL                       freeKeys,                       // true: free the keys on exit
+       const char                      *testStr)
+{
+       CSSM_RETURN                     crtn;
+       CSSM_CC_HANDLE          ccHand;
+       CSSM_DATA                       keyLabelData = {4, (uint8 *)"foo"};
+       int                                     irtn;
+       
+       memset(pubKey, 0, sizeof(CSSM_KEY));
+       memset(privKey, 0, sizeof(CSSM_KEY));
+
+       crtn = CSSM_CSP_CreateKeyGenContext(cspHand,
+               algorithm,
+               keySizeInBits,
+               NULL,                                   // Seed
+               NULL,                                   // Salt
+               NULL,                                   // StartDate
+               NULL,                                   // EndDate
+               NULL,                                   // Params
+               &ccHand);
+       if(crtn) {
+               printError("CSSM_CSP_CreateKeyGenContext", crtn);
+               return testError(quiet);
+       }
+
+       /* post-context-create algorithm-specific stuff */
+       switch(algorithm) {
+               case CSSM_ALGID_RSA:
+                       break;
+                
+                case CSSM_ALGID_DSA:
+                       /* 
+                        * extra step - generate params - this just adds some
+                        * info to the context
+                        */
+                       {
+                               CSSM_DATA dummy = {0, NULL};
+                               crtn = CSSM_GenerateAlgorithmParams(ccHand, 
+                                       keySizeInBits, &dummy);
+                               if(crtn) {
+                                       printError("CSSM_GenerateAlgorithmParams", crtn);
+                                       return testError(quiet);
+                               }
+                               appFreeCssmData(&dummy, CSSM_FALSE);
+                       }
+                       break;
+               default:
+                       break;
+       }
+       
+       crtn = CSSM_GenerateKeyPair(ccHand,
+               pubKeyUsage,
+               pubKeyAttr,
+               &keyLabelData,
+               pubKey,
+               privKeyUsage,
+               privKeyAttr,
+               &keyLabelData,                  // same labels
+               NULL,                                   // CredAndAclEntry
+               privKey);
+       if(crtn != expectRtn) {
+               printf("***Testing %s for alg %s:\n", testStr, keyAlgStr);
+               printf("   CSSM_GenerateKeyPair: expect %s\n",  cssmErrToStr(expectRtn));
+               printf("   CSSM_GenerateKeyPair: got    %s\n",  cssmErrToStr(crtn));
+               irtn = testError(quiet);
+       }
+       else {
+               irtn = 0;
+       }
+       CSSM_DeleteContext(ccHand);
+       if(freeKeys && (crtn == CSSM_OK)) {
+               cspFreeKey(cspHand, pubKey);
+               cspFreeKey(cspHand, privKey);
+       }
+       return irtn;
+}
+
+/* 
+ * Perform NULL wrap, generally expecting an error (either 
+ * CSSMERR_CSP_INVALID_KEYATTR_MASK, if the raw key bits should be inaccessible,
+ * or CSSMERR_CSP_INVALID_KEY_REFERENCE, if the key's header has been munged.)
+ */
+int nullWrapTest(
+       CSSM_CSP_HANDLE cspHand,
+       CSSM_KEY_PTR    key,
+       CSSM_BOOL               quiet,
+       CSSM_RETURN             expectRtn,
+       const char              *keyAlgStr,
+       const char              *testStr)
+{
+       CSSM_CC_HANDLE                          ccHand;
+       CSSM_RETURN                                     crtn;
+       CSSM_ACCESS_CREDENTIALS         creds;
+       CSSM_KEY                                        wrappedKey;             // should not get created
+       int                                                     irtn;
+       
+       memset(&wrappedKey, 0, sizeof(CSSM_KEY));
+       memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
+       crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
+                       CSSM_ALGID_NONE,
+                       CSSM_ALGMODE_NONE,
+                       &creds,                         // passPhrase,
+                       NULL,                           // wrappingKey,
+                       NULL,                           // IV
+                       CSSM_PADDING_NONE,      
+                       0,                                      // Params
+                       &ccHand);
+       if(crtn) {
+               printError("cspWrapKey/CreateContext", crtn);
+               return testError(quiet);
+       }
+       crtn = CSSM_WrapKey(ccHand,
+               &creds,
+               key,
+               NULL,                           // DescriptiveData
+               &wrappedKey);
+       if(crtn != expectRtn) {
+               printf("***Testing %s for alg %s:\n", testStr, keyAlgStr);
+               printf("   CSSM_WrapKey: expect %s\n",  cssmErrToStr(expectRtn));
+               printf("   CSSM_WrapKey: got    %s\n",  cssmErrToStr(crtn));
+               irtn = testError(quiet);
+       }
+       else {
+               irtn = 0;
+       }
+       CSSM_DeleteContext(ccHand);
+       return irtn;
+}
+
+/* 
+ * Attempt to wrap incoming key with a DES key that we generate. Expect
+ * CSSMERR_CSP_INVALID_KEYATTR_MASK since the unwrapped key is marked 
+ * !EXTRACTABLE.
+ */
+#define WRAPPING_KEY_ALG       CSSM_ALGID_DES
+#define WRAPPING_KEY_SIZE      CSP_DES_KEY_SIZE_DEFAULT
+
+static int badWrapTest(
+       CSSM_CSP_HANDLE         cspHand,
+       CSSM_KEY_PTR            unwrappedKey,
+       CSSM_KEYBLOB_FORMAT     wrapForm,
+       CSSM_BOOL                       quiet,
+       const char                      *keyAlgStr,
+       const char                      *testStr)
+{
+       CSSM_CC_HANDLE                          ccHand;
+       CSSM_RETURN                                     crtn;
+       CSSM_ACCESS_CREDENTIALS         creds;
+       CSSM_KEY                                        wrappedKey;             // should not get created
+       CSSM_KEY                                        wrappingKey;
+       int                                                     irtn;
+               
+       /* first generate a DES wrapping key */
+       if(genSymKey(cspHand, &wrappingKey, CSSM_ALGID_DES, "DES", 
+                       CSP_DES_KEY_SIZE_DEFAULT, 
+                       CSSM_KEYATTR_RETURN_REF,
+                       CSSM_KEYUSE_ANY, CSSM_OK, quiet, 
+                       CSSM_FALSE, "not a test case")) {
+               return 1;
+       }
+
+       memset(&wrappedKey, 0, sizeof(CSSM_KEY));
+       memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
+       
+       /* symmetric wrapping context */
+       crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
+                       CSSM_ALGID_DES,
+                       CSSM_ALGMODE_CBCPadIV8,
+                       &creds,                         // passPhrase,
+                       &wrappingKey,   
+                       NULL,                           // IV
+                       CSSM_PADDING_PKCS5,     
+                       0,                                      // Params
+                       &ccHand);
+       if(crtn) {
+               printError("cspWrapKey/CreateContext", crtn);
+               return testError(quiet);
+       }
+       
+       /* do it, demand error */
+       crtn = CSSM_WrapKey(ccHand,
+               &creds,
+               unwrappedKey,
+               NULL,                           // DescriptiveData
+               &wrappedKey);
+       if(crtn != CSSMERR_CSP_INVALID_KEYATTR_MASK) {
+               printf("***Testing %s for alg %s:\n", testStr, keyAlgStr);
+               printf("   CSSM_WrapKey: expect CSSMERR_CSP_INVALID_KEYATTR_MASK, got %s\n",
+                       cssmErrToStr(crtn));
+               irtn = testError(quiet);
+       }
+       else {
+               irtn = 0;
+       }
+       CSSM_DeleteContext(ccHand);
+       cspFreeKey(cspHand, &wrappingKey);
+       return irtn;
+}
+
+
+/*
+ * Note for these op stubs, the data, mode, padding, etc. are unimportant as 
+ * the ops are expected to fail during key extraction. 
+ */ 
+static int badEncrypt(
+       CSSM_CSP_HANDLE cspHand,
+       CSSM_KEY_PTR    key,
+       const char              *keyAlgStr,
+       CSSM_ALGORITHMS opAlg,
+       CSSM_RETURN             expectRtn,
+       CSSM_BOOL               quiet,
+       const char              *goodUseStr,
+       const char              *badUseStr)
+{
+       CSSM_CC_HANDLE  cryptHand;
+       CSSM_DATA               ptext = {4, (uint8 *)"foo"};
+       CSSM_DATA               ctext = {0, NULL};
+       CSSM_DATA               remData = {0, NULL};
+       CSSM_RETURN             crtn;
+       CSSM_SIZE               bytesEncrypted;
+       int                             irtn;
+       
+       cryptHand = genCryptHandle(cspHand, opAlg, CSSM_ALGMODE_NONE, CSSM_PADDING_NONE,
+               key, NULL /* key2 */, NULL /* iv */, 0, 0);
+       if(cryptHand == 0) {
+               return testError(quiet);
+       }
+       crtn = CSSM_EncryptData(cryptHand, &ptext, 1, &ctext, 1, &bytesEncrypted, &remData);
+       if(crtn != expectRtn) {
+               printf("***Testing %s key w/%s during %s:\n", keyAlgStr, goodUseStr, badUseStr);
+               printf("   CSSM_EncryptData: expect %s\n",      cssmErrToStr(expectRtn));
+               printf("   CSSM_EncryptData: got    %s\n",  cssmErrToStr(crtn));
+               irtn = testError(quiet);
+       }
+       else {
+               irtn = 0;
+       }
+       /* assume no ctext or remdata - OK? */
+       CSSM_DeleteContext(cryptHand);
+       return irtn;
+}
+
+static int badDecrypt(
+       CSSM_CSP_HANDLE cspHand,
+       CSSM_KEY_PTR    key,
+       const char              *keyAlgStr,
+       CSSM_ALGORITHMS opAlg,
+       CSSM_RETURN             expectRtn,
+       CSSM_BOOL               quiet,
+       const char              *goodUseStr,
+       const char              *badUseStr)
+{
+       CSSM_CC_HANDLE  cryptHand;
+       CSSM_DATA               ctext = {4, (uint8 *)"foo"};
+       CSSM_DATA               ptext = {0, NULL};
+       CSSM_DATA               remData = {0, NULL};
+       CSSM_RETURN             crtn;
+       CSSM_SIZE               bytesDecrypted;
+       int                             irtn;
+       
+       
+       cryptHand = genCryptHandle(cspHand, opAlg, CSSM_ALGMODE_NONE, CSSM_PADDING_NONE,
+               key, NULL /* key2 */, NULL /* iv */, 0, 0);
+       if(cryptHand == 0) {
+               return testError(quiet);
+       }
+       crtn = CSSM_DecryptData(cryptHand, &ctext, 1, &ptext, 1, &bytesDecrypted, &remData);
+       if(crtn != expectRtn) {
+               printf("***Testing %s key w/%s during %s:\n", keyAlgStr, goodUseStr, badUseStr);
+               printf("   CSSM_DecryptData: expect %s\n",      cssmErrToStr(expectRtn));
+               printf("   CSSM_DecryptData: got    %s\n",  cssmErrToStr(crtn));
+               irtn = testError(quiet);
+       }
+       else {
+               irtn = 0;
+       }
+       /* assume no ptext or remdata - OK? */
+       CSSM_DeleteContext(cryptHand);
+       return irtn;
+}
+
+/*
+ * Given a reference key (any class, any alg), attempt to perform null wrap after
+ * munging various fields in the header. Every attempt should result in
+ * CSSMERR_CSP_INVALID_KEY_REFERENCE.
+ */
+static int badHdrTest(
+       CSSM_CSP_HANDLE         cspHand,
+       CSSM_KEY_PTR            key, 
+       CSSM_BOOL                       quiet,
+       const char                      *keyAlgStr)
+{
+       CSSM_KEYHEADER  *hdr = &key->KeyHeader;
+       CSSM_KEYHEADER  savedHdr = *hdr;
+
+       hdr->HeaderVersion++;
+       if(nullWrapTest(cspHand, key, quiet, CSSMERR_CSP_INVALID_KEY_REFERENCE,
+                       keyAlgStr, "Munged hdr(HeaderVersion)")) {
+               return 1;
+       }
+       *hdr = savedHdr;
+
+       hdr->CspId.Data1++;
+       if(nullWrapTest(cspHand, key, quiet, CSSMERR_CSP_INVALID_KEY_REFERENCE,
+                       keyAlgStr, "Munged hdr(CspId.Data1)")) {
+               return 1;
+       }
+       *hdr = savedHdr;
+
+       /* can't test BlobType for Format, they're known to differ */
+       
+       hdr->AlgorithmId++;
+       if(nullWrapTest(cspHand, key, quiet, CSSMERR_CSP_INVALID_KEY_REFERENCE,
+                       keyAlgStr, "Munged hdr(AlgorithmId)")) {
+               return 1;
+       }
+       *hdr = savedHdr;
+
+       /* have to come up with valid KeyClass here */
+       switch(hdr->KeyClass) {
+               case CSSM_KEYCLASS_PUBLIC_KEY:
+                       hdr->KeyClass = CSSM_KEYCLASS_PRIVATE_KEY; break;
+               case CSSM_KEYCLASS_PRIVATE_KEY:
+                       hdr->KeyClass = CSSM_KEYCLASS_SESSION_KEY; break;
+               case CSSM_KEYCLASS_SESSION_KEY:
+                       hdr->KeyClass = CSSM_KEYCLASS_PUBLIC_KEY; break;
+               default:
+                       printf("***BRZZAP! badHdrTest needs work\n");
+                       exit(1);
+       }
+       if(nullWrapTest(cspHand, key, quiet, CSSMERR_CSP_INVALID_KEY_REFERENCE,
+                       keyAlgStr, "Munged hdr(KeyClass)")) {
+               return 1;
+       }
+       *hdr = savedHdr;
+
+       hdr->LogicalKeySizeInBits++;
+       if(nullWrapTest(cspHand, key, quiet, CSSMERR_CSP_INVALID_KEY_REFERENCE,
+                       keyAlgStr, "Munged hdr(LogicalKeySizeInBits)")) {
+               return 1;
+       }
+       *hdr = savedHdr;
+
+       hdr->KeyAttr++;
+       if(nullWrapTest(cspHand, key, quiet, CSSMERR_CSP_INVALID_KEY_REFERENCE,
+                       keyAlgStr, "Munged hdr(KeyAttr)")) {
+               return 1;
+       }
+       *hdr = savedHdr;
+
+       hdr->StartDate.Day[0]++;
+       if(nullWrapTest(cspHand, key, quiet, CSSMERR_CSP_INVALID_KEY_REFERENCE,
+                       keyAlgStr, "Munged hdr(StartDate.Day)")) {
+               return 1;
+       }
+       *hdr = savedHdr;
+
+       hdr->EndDate.Year[1]++;
+       if(nullWrapTest(cspHand, key, quiet, CSSMERR_CSP_INVALID_KEY_REFERENCE,
+                       keyAlgStr, "Munged hdr(EndDate.Year)")) {
+               return 1;
+       }
+       *hdr = savedHdr;
+
+       hdr->WrapAlgorithmId++;
+       if(nullWrapTest(cspHand, key, quiet, CSSMERR_CSP_INVALID_KEY_REFERENCE,
+                       keyAlgStr, "Munged hdr(WrapAlgorithmId)")) {
+               return 1;
+       }
+       *hdr = savedHdr;
+
+       hdr->WrapMode++;
+       if(nullWrapTest(cspHand, key, quiet, CSSMERR_CSP_INVALID_KEY_REFERENCE,
+                       keyAlgStr, "Munged hdr(WrapMode)")) {
+               return 1;
+       }
+       *hdr = savedHdr;
+
+       return 0;
+}
+
+/*
+ * Given some op alg, return a different op alg which is of the same class
+ * but should not work with an opAlg-related key.
+ */
+CSSM_ALGORITHMS badOpAlg(
+       CSSM_ALGORITHMS opAlg)
+{
+       switch(opAlg) {
+               /* symmetric block ciphers */
+               case CSSM_ALGID_DES: return CSSM_ALGID_3DES_3KEY_EDE;
+               case CSSM_ALGID_3DES_3KEY_EDE: return CSSM_ALGID_RC2;
+               case CSSM_ALGID_RC2: return CSSM_ALGID_RC5;
+               case CSSM_ALGID_RC5: return CSSM_ALGID_AES;
+               case CSSM_ALGID_AES: return CSSM_ALGID_DES;
+
+               /* symmetric stream ciphers */
+               case CSSM_ALGID_ASC: return CSSM_ALGID_RC4;     
+               case CSSM_ALGID_RC4: return CSSM_ALGID_ASC;     
+               
+               /* asymmetric ciphers */
+               case CSSM_ALGID_RSA: return CSSM_ALGID_FEEDEXP;
+               case CSSM_ALGID_FEEDEXP: return CSSM_ALGID_RSA;
+               
+               /* digital signature */
+               case CSSM_ALGID_SHA1WithRSA: return CSSM_ALGID_SHA1WithDSA;
+               case CSSM_ALGID_SHA1WithDSA: return CSSM_ALGID_SHA1WithECDSA;
+               case CSSM_ALGID_SHA1WithECDSA: return CSSM_ALGID_SHA1WithRSA;
+               
+               default: printf("***BRRZAP! badOpAlg needs work.\n"); exit(1);
+       }
+       /* NOT REACHED */
+       return 0;
+}
+
+/*
+ * -- Generate symmetric key with specified alg and usage;
+ * -- Verify that it can't be used for any of the ops specified 
+ *    in badOpFlags using goodEncrAlg/goodSignAlg;
+ * -- Verify that it can't be used for goodOp/badAlg;
+ *
+ * Used by symUsageTest().
+ *
+ */
+#define SYM_USAGE_ENABLE       1
+static int badSymUsage(
+       CSSM_CSP_HANDLE cspHand,
+       CSSM_ALGORITHMS keyAlg,                 // alg of the key
+       const char              *keyAlgStr, 
+       uint32                  keySizeInBits,
+       CSSM_KEYUSE             keyUse,                 // gen key with this usage
+       CSSM_ALGORITHMS goodEncrAlg,    // key is good for this encryption alg
+       CSSM_ALGORITHMS goodSignAlg,    // key is good for this sign alg (may not be used)
+       unsigned                badOpFlags,             // array of (OP_DECRYPT,...)
+       unsigned                goodOp,                 // one good op...
+       CSSM_ALGORITHMS badAlg,                 // ..which fails for this alg
+       CSSM_BOOL               quiet,
+       const char              *useStr)
+{
+       CSSM_KEY                symKey;
+       int                             irtn;
+       
+       if(genSymKey(cspHand, &symKey, keyAlg, keyAlgStr, keySizeInBits,
+                       CSSM_KEYATTR_RETURN_REF, keyUse, CSSM_OK, quiet, CSSM_FALSE, useStr)) {
+               return 1;
+       }
+       #if             SYM_USAGE_ENABLE
+       if(!quiet) {
+               printf("         ...testing key usage\n");
+       }
+       if(badOpFlags & OP_ENCRYPT) {
+               irtn = badEncrypt(cspHand, &symKey, keyAlgStr, goodEncrAlg,
+                       CSSMERR_CSP_KEY_USAGE_INCORRECT, quiet, useStr, "ENCRYPT");
+               if(irtn) {
+                       goto abort;
+               }
+       }
+       if(badOpFlags & OP_DECRYPT) {
+               irtn = badDecrypt(cspHand, &symKey, keyAlgStr, goodEncrAlg,
+                       CSSMERR_CSP_KEY_USAGE_INCORRECT, quiet, useStr, "DECRYPT");
+               if(irtn) {
+                       goto abort;
+               }
+       }
+       #endif  /* SYM_USAGE_ENABLE */
+       
+       /* now do a good op with an incorrect algorithm */
+       if(!quiet) {
+               printf("         ...testing key/algorithm match\n");
+       }
+       if(goodOp & OP_ENCRYPT) {
+               irtn = badEncrypt(cspHand, &symKey, keyAlgStr, badAlg,
+                       CSSMERR_CSP_ALGID_MISMATCH, quiet, useStr, "ENCRYPT w/bad alg");
+               if(irtn) {
+                       goto abort;
+               }
+       }
+       if(goodOp & OP_DECRYPT) {
+               irtn = badDecrypt(cspHand, &symKey, keyAlgStr, badAlg,
+                       CSSMERR_CSP_ALGID_MISMATCH, quiet, useStr, "DECRYPT w/bad alg");
+               if(irtn) {
+                       goto abort;
+               }
+       }
+abort:
+       cspFreeKey(cspHand, &symKey);
+       return irtn;
+}
+
+/* 
+ * Verify symmetric key usage behavior:
+ *
+ *     gen key with KEYUSE_ENCRYPT
+ *             make sure you can't use it for decrypt
+ *             make sure you can't use it for encrypting with other alg
+ *     gen key with KEYUSE_DECRYPT
+ *             make sure you can't use it for encrypt
+ *             make sure you can't use it for decrypting with other alg
+ *     gen key with KEYUSE_SIGN (mac)
+ *             make sure you can't use it for encrypt or decrypt
+ *     gen key with KEYUSE_VERIFY (mac verify)
+ *             make sure you can't use it for encrypt or decrypt
+ */
+int symUsageTest(
+       CSSM_CSP_HANDLE cspHand,
+       CSSM_ALGORITHMS keyAlg,
+       const char              *keyAlgStr,
+       CSSM_ALGORITHMS encrAlg,
+       CSSM_ALGORITHMS signAlg,
+       uint32                  keySizeInBits,
+       CSSM_BOOL               quiet)
+{
+       if(!quiet) {
+               printf("      ...testing encrypt-enabled key\n");
+       }
+       if(badSymUsage(cspHand, keyAlg, keyAlgStr, keySizeInBits, CSSM_KEYUSE_ENCRYPT,
+                       encrAlg, signAlg, OP_DECRYPT, OP_ENCRYPT, badOpAlg(encrAlg), 
+                       quiet, "ENCRYPT")) {
+               return 1;
+       }
+       if(!quiet) {
+               printf("      ...testing decrypt-enabled key\n");
+       }
+       if(badSymUsage(cspHand, keyAlg, keyAlgStr, keySizeInBits, CSSM_KEYUSE_DECRYPT,
+                       encrAlg, signAlg, OP_ENCRYPT, OP_DECRYPT, badOpAlg(encrAlg), 
+                       quiet, "DECRYPT")) {
+               return 1;
+       }
+       return 0;
+}
+
+/* 
+ * Verify symmetric key attribute behavior:
+ *
+ *     check that you can not gen a key with {
+ *             CSSM_KEYATTR_ALWAYS_SENSITIVE
+ *             CSSM_KEYATTR_NEVER_EXTRACTABLE
+ *             CSSM_KEYATTR_PERMANENT
+ *             CSSM_KEYATTR_PRIVATE
+ *             CSSM_KEYATTR_RETURN_DATA | !CSSM_KEYATTR_EXTRACTABLE
+ *             CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_SENSITIVE
+ *             CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_RETURN_REF
+ *     }
+ */
+int symAttrTest(
+       CSSM_CSP_HANDLE cspHand,
+       CSSM_ALGORITHMS alg,
+       const char              *keyAlgStr,
+       uint32                  keySizeInBits,
+       CSSM_BOOL               bareCsp,
+       CSSM_BOOL               quiet)
+{
+       CSSM_KEY key;
+       
+       if(!quiet) {
+               printf("      ...testing key attr\n");
+       }
+       if(bareCsp || CSPDL_ALWAYS_SENSITIVE_CHECK) {
+               if(genSymKey(cspHand, &key, alg, keyAlgStr, keySizeInBits, 
+                               CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_ALWAYS_SENSITIVE,
+                               CSSM_KEYUSE_ANY, CSSMERR_CSP_INVALID_KEYATTR_MASK, quiet,
+                               CSSM_TRUE, "ALWAYS_SENSITIVE")) {
+                       return 1;
+               }       
+       }
+       if(bareCsp || CSPDL_NEVER_EXTRACTABLE_CHECK) {
+               if(genSymKey(cspHand, &key, alg, keyAlgStr, keySizeInBits, 
+                               CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_NEVER_EXTRACTABLE,
+                               CSSM_KEYUSE_ANY, CSSMERR_CSP_INVALID_KEYATTR_MASK, quiet,
+                               CSSM_TRUE, "NEVER_EXTRACTABLE")) {
+                       return 1;
+               }
+       }
+       /*
+        * bare CSP : CSSMERR_CSP_UNSUPPORTED_KEYATTR_MASK
+        * CSPDL    : CSSMERR_CSP_MISSING_ATTR_DL_DB_HANDLE
+        */
+       if(genSymKey(cspHand, &key, alg, keyAlgStr, keySizeInBits, 
+                       CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_PERMANENT,
+                       CSSM_KEYUSE_ANY,
+                       bareCsp ?  CSSMERR_CSP_UNSUPPORTED_KEYATTR_MASK : 
+                               CSSMERR_CSP_MISSING_ATTR_DL_DB_HANDLE,
+                       quiet,
+                       CSSM_TRUE, "PERMANENT")) {
+               return 1;
+       }
+       if(genSymKey(cspHand, &key, alg, keyAlgStr, keySizeInBits, 
+                       CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_PRIVATE,
+                       CSSM_KEYUSE_ANY, CSSMERR_CSP_UNSUPPORTED_KEYATTR_MASK, quiet,
+                       CSSM_TRUE, "PRIVATE")) {
+               return 1;
+       }
+       if(bareCsp) {
+               /* CSPDL doesn't support RETURN_DATA */
+               if(genSymKey(cspHand, &key, alg, keyAlgStr, keySizeInBits, 
+                               CSSM_KEYATTR_RETURN_DATA /* and !extractable */,
+                               CSSM_KEYUSE_ANY, 
+                               CSSMERR_CSP_INVALID_KEYATTR_MASK, quiet,
+                               CSSM_TRUE, "RETURN_DATA | !EXTRACTABLE")) {
+                       return 1;
+               }
+               if(genSymKey(cspHand, &key, alg, keyAlgStr, keySizeInBits, 
+                               CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_SENSITIVE,
+                               CSSM_KEYUSE_ANY, CSSMERR_CSP_INVALID_KEYATTR_MASK, quiet,
+                               CSSM_TRUE, "RETURN_DATA | SENSITIVE")) {
+                       return 1;
+               }
+               if(genSymKey(cspHand, &key, alg, keyAlgStr, keySizeInBits, 
+                               CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_RETURN_REF,
+                               CSSM_KEYUSE_ANY, CSSMERR_CSP_INVALID_KEYATTR_MASK, quiet,
+                               CSSM_TRUE, "RETURN_DATA | RETURN_REF")) {
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+/*
+ * Verify proper symmetric key null wrap operation.
+ *
+ *     gen ref key, CSSM_KEYATTR_SENSITIVE, vfy you can't do null wrap;
+ *     gen ref key, !CSSM_KEYATTR_EXTRACTABLE, vfy you can't do null wrap;
+ */
+int symNullWrapTest(
+       CSSM_CSP_HANDLE cspHand,
+       CSSM_ALGORITHMS alg,
+       const char              *keyAlgStr,
+       uint32                  keySizeInBits,
+       CSSM_BOOL               quiet)
+{
+       CSSM_KEY key;
+
+       if(!quiet) {
+               printf("      ...testing access to inaccessible key bits via NULL wrap\n");
+       }
+       
+       /* gen ref key, CSSM_KEYATTR_SENSITIVE, vfy you can't do null wrap */
+       if(genSymKey(cspHand, &key, alg, keyAlgStr, keySizeInBits, 
+                       CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_SENSITIVE,
+                       CSSM_KEYUSE_ANY, CSSM_OK, quiet, 
+                       CSSM_FALSE, "SENSITIVE | RETURN_REF")) {
+               return 1;
+       }
+       if(nullWrapTest(cspHand, &key, quiet, CSSMERR_CSP_INVALID_KEYATTR_MASK,
+                       keyAlgStr, "KEYATTR_SENSITIVE")) {
+               return 1;
+       }
+       cspFreeKey(cspHand, &key);
+       
+       /* gen ref key, !CSSM_KEYATTR_EXTRACTABLE, vfy you can't do null wrap */
+       if(genSymKey(cspHand, &key, alg, keyAlgStr, keySizeInBits, 
+                       CSSM_KEYATTR_RETURN_REF /* !CSSM_KEYATTR_EXTRACTABLE */,
+                       CSSM_KEYUSE_ANY, CSSM_OK, quiet, 
+                       CSSM_FALSE, "!EXTRACTABLE | RETURN_REF")) {
+               return 1;
+       }
+       if(nullWrapTest(cspHand, &key, quiet, CSSMERR_CSP_INVALID_KEYATTR_MASK,
+                       keyAlgStr, "!EXTRACTABLE")) {
+               return 1;
+       }
+       cspFreeKey(cspHand, &key);
+
+       return 0;
+}
+
+/*
+ * Verify proper symmetric key wrap !EXTRACTABLE handling.
+ *
+ * Gen unwrapped ref key, !CSSM_KEYATTR_EXTRACTABLE;
+ * Gen wrapping key - a simple DES key;
+ * vfy you can't wrap unwrappedKey with wrappingKey;
+ */
+int symBadWrapTest(
+       CSSM_CSP_HANDLE cspHand,
+       CSSM_ALGORITHMS alg,
+       const char              *keyAlgStr,
+       uint32                  keySizeInBits,
+       CSSM_BOOL               quiet)
+{
+       CSSM_KEY unwrappedKey;
+       
+       if(!quiet) {
+               printf("      ...testing access to !EXTRACTABLE key bits via PKCS7 wrap\n");
+       }
+       
+       /* gen ref key, CSSM_KEYATTR_SENSITIVE, !EXTRACTABLE */
+       if(genSymKey(cspHand, &unwrappedKey, alg, keyAlgStr, keySizeInBits, 
+                       CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_SENSITIVE,
+                       CSSM_KEYUSE_ANY, CSSM_OK, quiet, 
+                       CSSM_FALSE, "SENSITIVE | RETURN_REF")) {
+               return 1;
+       }
+       if(badWrapTest(cspHand, 
+               &unwrappedKey, 
+               CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7,
+               quiet, keyAlgStr, 
+               "!EXTRACTABLE wrap")) {
+               return 1;
+       }
+       cspFreeKey(cspHand, &unwrappedKey);
+       return 0;
+}
+
+/*
+ * Verify proper asymmetric key wrap !EXTRACTABLE handling.
+ *
+ * Gen unwrapped ref key, !CSSM_KEYATTR_EXTRACTABLE;
+ * Gen wrapping key - a simple DES key;
+ * vfy you can't wrap unwrappedKey with wrappingKey;
+ */
+int asymBadWrapTest(
+       CSSM_CSP_HANDLE cspHand,
+       CSSM_ALGORITHMS alg,
+       const char              *keyAlgStr,
+       uint32                  keySizeInBits,
+       CSSM_BOOL               quiet)
+{
+       CSSM_KEY pubKey;
+       CSSM_KEY privKey;
+       
+       if(!quiet) {
+               printf("      ...testing access to !EXTRACTABLE key bits via CUSTOM wrap\n");
+       }
+       
+       /* gen ref key, CSSM_KEYATTR_SENSITIVE, !EXTRACTABLE */
+       if(genKeyPair(cspHand, alg, keyAlgStr, keySizeInBits, 
+                       &pubKey, CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE, 
+                               CSSM_KEYUSE_ANY, 
+                       &privKey, CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_SENSITIVE, 
+                               CSSM_KEYUSE_ANY, 
+                       CSSM_OK, quiet, CSSM_FALSE, "RETURN_REF | SENSITIVE")) {
+               return 1;
+       }       
+       if(badWrapTest(cspHand, 
+               &privKey, 
+               CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM,
+               quiet, keyAlgStr, 
+               "!EXTRACTABLE wrap")) {
+               return 1;
+       }
+       cspFreeKey(cspHand, &privKey);
+       cspFreeKey(cspHand, &pubKey);
+       return 0;
+}
+
+/*
+ * Generate a ref key, munge various fields in the header, verify that attempts
+ * to use the munged key result in CSSMERR_CSP_INVALID_KEY_REFERENCE.
+ */
+int symHeaderTest(
+       CSSM_CSP_HANDLE cspHand,
+       CSSM_ALGORITHMS keyAlg,
+       const char              *keyAlgStr,
+       CSSM_ALGORITHMS encrAlg,
+       CSSM_ALGORITHMS signAlg,
+       uint32                  keySizeInBits,
+       CSSM_BOOL               quiet)
+{
+       CSSM_KEY key;
+
+       if(!quiet) {
+               printf("      ...testing munged ref key header\n");
+       }
+       if(genSymKey(cspHand, &key, keyAlg, keyAlgStr, keySizeInBits, 
+                       CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE,
+                       CSSM_KEYUSE_ANY, CSSM_OK, quiet, 
+                       CSSM_FALSE, "RETURN_REF")) {
+               return 1;
+       }
+       if(badHdrTest(cspHand, &key, quiet, keyAlgStr)) {
+               return 1;
+       }
+       cspFreeKey(cspHand, &key);
+       return 0;
+}
+
+/*
+ * Generate key pair, specified pub key attr and expected result, standard
+ * "good" priv key attr. Used by asymAttrTest().
+ */
+static int pubKeyAttrTest(
+       CSSM_CSP_HANDLE         cspHand,
+       CSSM_ALGORITHMS         alg,
+       const char                      *keyAlgStr,
+       uint32                          keySizeInBits,
+       CSSM_KEYATTR_FLAGS      pubKeyAttr,
+       CSSM_RETURN                     expectRtn,
+       CSSM_BOOL                       quiet,
+       const char                      *testStr)
+{
+       CSSM_KEY pubKey;
+       CSSM_KEY privKey;
+       
+       return genKeyPair(cspHand, alg, keyAlgStr, keySizeInBits, 
+                       &pubKey, pubKeyAttr, CSSM_KEYUSE_ANY, 
+                       &privKey, CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_SENSITIVE, CSSM_KEYUSE_ANY, 
+                       expectRtn, quiet, CSSM_TRUE, testStr);
+}
+
+/*
+ * Generate key pair, specified priv key attr and expected result, standard
+ * "good" pub key attr. Used by asymAttrTest().
+ */
+static int privKeyAttrTest(
+       CSSM_CSP_HANDLE         cspHand,
+       CSSM_ALGORITHMS         alg,
+       const char                      *keyAlgStr,
+       uint32                          keySizeInBits,
+       CSSM_KEYATTR_FLAGS      privKeyAttr,
+       CSSM_RETURN                     expectRtn,
+       CSSM_BOOL                       quiet,
+       const char                      *testStr)
+{
+       CSSM_KEY pubKey;
+       CSSM_KEY privKey;
+       
+       return genKeyPair(cspHand, alg, keyAlgStr, keySizeInBits, 
+                       &pubKey, CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE, 
+                               CSSM_KEYUSE_ANY, 
+                       &privKey, privKeyAttr, CSSM_KEYUSE_ANY,
+                       expectRtn, quiet, CSSM_TRUE, testStr);
+}
+
+/*
+ * Verify asymmetric key attribute behavior.
+ *
+ *     check that you can't gen pub key with {
+ *             CSSM_KEYATTR_ALWAYS_SENSITIVE
+ *             CSSM_KEYATTR_NEVER_EXTRACTABLE
+ *             CSSM_KEYATTR_PERMANENT
+ *             CSSM_KEYATTR_PRIVATE
+ *             CSSM_KEYATTR_RETURN_DATA | !CSSM_KEYATTR_EXTRACTABLE
+ *             CSSM_KEYATTR_RETURN_REF  | !CSSM_KEYATTR_EXTRACTABLE
+ *             CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_SENSITIVE
+ *             CSSM_KEYATTR_RETURN_REF  | CSSM_KEYATTR_SENSITIVE
+ *     }
+ *     check that you can't gen priv key with {
+ *             CSSM_KEYATTR_ALWAYS_SENSITIVE
+ *             CSSM_KEYATTR_NEVER_EXTRACTABLE
+ *             CSSM_KEYATTR_PERMANENT
+ *             CSSM_KEYATTR_PRIVATE
+ *             CSSM_KEYATTR_RETURN_DATA | !CSSM_KEYATTR_EXTRACTABLE
+ *             CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_SENSITIVE
+ *     }
+ */
+static int asymAttrTest(
+       CSSM_CSP_HANDLE cspHand,
+       CSSM_ALGORITHMS alg,
+       const char              *keyAlgStr,
+       uint32                  keySizeInBits,
+       CSSM_BOOL               bareCsp,
+       CSSM_BOOL               quiet)
+{
+       #if CSPDL_ALL_KEYS_ARE_PERMANENT
+       printf("      ...SKIPING asymAttrTest due to Radar 3732910\n");
+       return 0;
+       #endif
+       if(!quiet) {
+               printf("      ...testing key attr\n");
+       }
+       if(bareCsp || CSPDL_ALWAYS_SENSITIVE_CHECK) {
+               if(pubKeyAttrTest(cspHand, alg, keyAlgStr, keySizeInBits,
+                               CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_ALWAYS_SENSITIVE,
+                               CSSMERR_CSP_INVALID_KEYATTR_MASK, quiet, "ALWAYS_SENSITIVE pub")) {
+                       return 1;
+               }       
+       }
+       if(bareCsp || CSPDL_NEVER_EXTRACTABLE_CHECK) {
+               if(pubKeyAttrTest(cspHand, alg, keyAlgStr, keySizeInBits, 
+                               CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_NEVER_EXTRACTABLE,
+                               CSSMERR_CSP_INVALID_KEYATTR_MASK, quiet, "NEVER_EXTRACTABLE pub")) {
+                       return 1;
+               }       
+       }
+       if(pubKeyAttrTest(cspHand, alg, keyAlgStr, keySizeInBits, 
+                       CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_PERMANENT | 
+                               CSSM_KEYATTR_EXTRACTABLE,
+                       bareCsp ?
+                               /* bare CSP - permanent is checked first, this is the error */
+                               CSSMERR_CSP_UNSUPPORTED_KEYATTR_MASK :
+                               /* CSPDL - SS strips off permanent, then does key gen (so we'd
+                                       * better specify EXTRACTABLE!), *then* checks for DLDB. */
+                               CSSMERR_CSP_MISSING_ATTR_DL_DB_HANDLE,
+               quiet, "PERMANENT pub")) {
+               return 1;
+       }       
+       if(pubKeyAttrTest(cspHand, alg, keyAlgStr, keySizeInBits, 
+                       CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_PRIVATE |
+                               CSSM_KEYATTR_EXTRACTABLE,
+                       CSSMERR_CSP_UNSUPPORTED_KEYATTR_MASK, quiet, "PRIVATE pub")) {
+               return 1;
+       }       
+       if(bareCsp) {
+               /* CSPDL doesn't support RETURN_DATA */
+               if(pubKeyAttrTest(cspHand, alg, keyAlgStr, keySizeInBits, 
+                               CSSM_KEYATTR_RETURN_DATA /* | !CSSM_KEYATTR_EXTRACTABLE */,
+                               CSSMERR_CSP_INVALID_KEYATTR_MASK, quiet, 
+                                       "RETURN_DATA | !EXTRACTABLE pub")) {
+                       return 1;
+               }
+       }       
+       /* pub key should always be extractable */ 
+       if(pubKeyAttrTest(cspHand, alg, keyAlgStr, keySizeInBits, 
+                       CSSM_KEYATTR_RETURN_REF /* | !CSSM_KEYATTR_EXTRACTABLE */,
+                       CSSMERR_CSP_INVALID_KEYATTR_MASK, quiet, 
+                               "RETURN_REF | !EXTRACTABLE pub")) {
+               return 1;
+       }       
+       /* pub keys can't be sensitive */
+       if(bareCsp) {
+               /* CSPDL doesn't support RETURN_DATA */
+               if(pubKeyAttrTest(cspHand, alg, keyAlgStr, keySizeInBits, 
+                               CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_SENSITIVE,
+                               CSSMERR_CSP_INVALID_KEYATTR_MASK, quiet, "RETURN_DATA | SENSITIVE pub")) {
+                       return 1;
+               }
+       }       
+       if(pubKeyAttrTest(cspHand, alg, keyAlgStr, keySizeInBits, 
+                       CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_SENSITIVE,
+                       CSSMERR_CSP_INVALID_KEYATTR_MASK, quiet, "RETURN_REF | !SENSITIVE pub")) {
+               return 1;
+       }       
+       
+       /* priv key attr tests */
+       if(bareCsp || CSPDL_ALWAYS_SENSITIVE_CHECK) {
+               if(privKeyAttrTest(cspHand, alg, keyAlgStr, keySizeInBits,
+                               CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_ALWAYS_SENSITIVE,
+                               CSSMERR_CSP_INVALID_KEYATTR_MASK, quiet, "ALWAYS_SENSITIVE priv")) {
+                       return 1;
+               }       
+       }
+       if(bareCsp || CSPDL_NEVER_EXTRACTABLE_CHECK) {
+               if(privKeyAttrTest(cspHand, alg, keyAlgStr, keySizeInBits,
+                               CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_NEVER_EXTRACTABLE,
+                               CSSMERR_CSP_INVALID_KEYATTR_MASK, quiet, "NEVER_EXTRACTABLE priv")) {
+                       return 1;
+               }       
+       }
+       if(privKeyAttrTest(cspHand, alg, keyAlgStr, keySizeInBits,
+                       CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_PERMANENT,
+                       bareCsp ?  CSSMERR_CSP_UNSUPPORTED_KEYATTR_MASK : 
+                               CSSMERR_CSP_MISSING_ATTR_DL_DB_HANDLE,
+                       quiet, "PERMANENT priv")) {
+               return 1;
+       }       
+       if(privKeyAttrTest(cspHand, alg, keyAlgStr, keySizeInBits,
+                       CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_PRIVATE,
+                       CSSMERR_CSP_UNSUPPORTED_KEYATTR_MASK, quiet, "PRIVATE priv")) {
+               return 1;
+       }       
+       if(bareCsp) {
+               /* CSPDL doesn't support RETURN_DATA */
+               if(privKeyAttrTest(cspHand, alg, keyAlgStr, keySizeInBits,
+                               CSSM_KEYATTR_RETURN_DATA /* | CSSM_KEYATTR_EXTRACTABLE */,
+                               CSSMERR_CSP_INVALID_KEYATTR_MASK, quiet, 
+                               "RETURN_DATA | !EXTRACTABLE priv")) {
+                       return 1;
+               }
+               if(privKeyAttrTest(cspHand, alg, keyAlgStr, keySizeInBits,
+                               CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_SENSITIVE,
+                               CSSMERR_CSP_INVALID_KEYATTR_MASK, quiet, "RETURN_DATA | SENSITIVE priv")) {
+                       return 1;
+               }       
+       }
+       return 0;
+}
+
+/* 
+ * Verify asymmetric key null wrap behavior:
+ *     gen ref key, CSSM_KEYATTR_SENSITIVE, vfy you can't do null wrap;
+ *     gen ref key, !CSSM_KEYATTR_EXTRACTABLE, vfy you can't do null wrap;
+ */
+static int asymNullWrapTest(
+       CSSM_CSP_HANDLE cspHand,
+       CSSM_ALGORITHMS alg,
+       const char              *keyAlgStr,
+       uint32                  keySizeInBits,
+       CSSM_BOOL               quiet)
+{
+       CSSM_KEY pubKey;
+       CSSM_KEY privKey;
+       
+       if(!quiet) {
+               printf("      ...testing access to inaccessible key bits via NULL wrap\n");
+       }
+       /* gen priv ref key, CSSM_KEYATTR_SENSITIVE, vfy you can't do null wrap */
+       if(genKeyPair(cspHand, alg, keyAlgStr, keySizeInBits, 
+                       &pubKey, CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE, 
+                               CSSM_KEYUSE_ANY, 
+                       &privKey, CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_SENSITIVE, 
+                               CSSM_KEYUSE_ANY, 
+                       CSSM_OK, quiet, CSSM_FALSE, "RETURN_REF | SENSITIVE")) {
+               return 1;
+       }       
+       if(nullWrapTest(cspHand, &privKey, quiet, CSSMERR_CSP_INVALID_KEYATTR_MASK,
+                       keyAlgStr, "SENSITIVE")) {
+               return 1;
+       }
+       cspFreeKey(cspHand, &privKey);
+       cspFreeKey(cspHand, &pubKey);
+       
+       /* gen priv ref key, !CSSM_KEYATTR_EXTRACTABLE, vfy you can't do null wrap */
+       if(genKeyPair(cspHand, alg, keyAlgStr, keySizeInBits, 
+                       &pubKey, CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE, 
+                               CSSM_KEYUSE_ANY, 
+                       &privKey, CSSM_KEYATTR_RETURN_REF /* | !EXTRACTABLE */, CSSM_KEYUSE_ANY, 
+                       CSSM_OK, quiet, CSSM_FALSE, "RETURN_REF | !EXTRACTABLE")) {
+               return 1;
+       }       
+       if(nullWrapTest(cspHand, &privKey, quiet, CSSMERR_CSP_INVALID_KEYATTR_MASK,
+                       keyAlgStr, "!EXTRACTABLE")) {
+               return 1;
+       }
+       cspFreeKey(cspHand, &privKey);
+       cspFreeKey(cspHand, &pubKey);
+       return 0;
+}
+
+/*
+ * Generate public and private ref keys, munge various fields in the header, 
+ * verify that attempts to use the munged key result in 
+ * CSSMERR_CSP_INVALID_KEY_REFERENCE.
+ */
+int asymHeaderTest(
+       CSSM_CSP_HANDLE cspHand,
+       CSSM_ALGORITHMS keyAlg,
+       const char              *keyAlgStr,
+       CSSM_ALGORITHMS encrAlg,
+       CSSM_ALGORITHMS signAlg,
+       uint32                  keySizeInBits,
+       CSSM_BOOL               quiet)
+{
+       CSSM_KEY privKey;
+       CSSM_KEY pubKey;
+
+       if(!quiet) {
+               printf("      ...testing munged ref key header\n");
+       }
+       if(genKeyPair(cspHand, keyAlg, keyAlgStr, keySizeInBits, 
+                       &pubKey, CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE, 
+                               CSSM_KEYUSE_ANY, 
+                       &privKey, CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE, 
+                               CSSM_KEYUSE_ANY, 
+                       CSSM_OK, quiet, CSSM_FALSE, "RETURN_REF")) {
+               return 1;
+       }       
+       if(badHdrTest(cspHand, &privKey, quiet, keyAlgStr)) {
+               return 1;
+       }
+       if(badHdrTest(cspHand, &pubKey, quiet, keyAlgStr)) {
+               return 1;
+       }
+       cspFreeKey(cspHand, &privKey);
+       cspFreeKey(cspHand, &pubKey);
+       return 0;
+}
+
+/* map one of our private privAlgs (ALG_DES, etc.) to associated CSSM info. */
+void privAlgToCssm(
+       privAlg                 palg,
+       CSSM_ALGORITHMS *keyAlg,
+       CSSM_ALGORITHMS *signAlg,               // CSSM_ALGID_NONE means incapable (e.g., DES)
+       CSSM_ALGORITHMS *encrAlg,               // CSSM_ALGID_NONE means incapable (e.g., DSA)
+       uint32                  *keySizeInBits,
+       const char              **keyAlgStr)
+{
+       *signAlg = *encrAlg = CSSM_ALGID_NONE;  // default
+       switch(palg) {
+               case ALG_ASC:
+                       *encrAlg = *keyAlg = CSSM_ALGID_ASC;
+                       *keySizeInBits = CSP_ASC_KEY_SIZE_DEFAULT;
+                       *keyAlgStr = "ASC";
+                       break;
+               case ALG_DES:
+                       *encrAlg = *keyAlg = CSSM_ALGID_DES;
+                       *keySizeInBits = CSP_DES_KEY_SIZE_DEFAULT;
+                       *keyAlgStr = "DES";
+                       break;
+               case ALG_3DES:
+                       *encrAlg = CSSM_ALGID_3DES_3KEY_EDE;
+                       *keyAlg = CSSM_ALGID_3DES_3KEY;
+                       *keySizeInBits = CSP_DES3_KEY_SIZE_DEFAULT;
+                       *keyAlgStr = "3DES";
+                       break;
+               case ALG_RC2:
+                       *encrAlg = *keyAlg = CSSM_ALGID_RC2;
+                       *keySizeInBits = CSP_RC2_KEY_SIZE_DEFAULT;
+                       *keyAlgStr = "RC2";
+                       break;
+               case ALG_RC4:
+                       *encrAlg = *keyAlg = CSSM_ALGID_RC4;
+                       *keySizeInBits = CSP_RC4_KEY_SIZE_DEFAULT;
+                       *keyAlgStr = "RC4";
+                       break;
+               case ALG_RC5:
+                       *encrAlg = *keyAlg = CSSM_ALGID_RC5;
+                       *keySizeInBits = CSP_RC5_KEY_SIZE_DEFAULT;
+                       *keyAlgStr = "RC5";
+                       break;
+               case ALG_AES:
+                       *encrAlg = *keyAlg = CSSM_ALGID_AES;
+                       *keySizeInBits = CSP_AES_KEY_SIZE_DEFAULT;
+                       *keyAlgStr = "AES";
+                       break;
+               case ALG_RSA:
+                       *keyAlg = CSSM_ALGID_RSA;
+                       *encrAlg = CSSM_ALGID_RSA;
+                       *signAlg = CSSM_ALGID_SHA1WithRSA;
+                       *keySizeInBits = CSP_RSA_KEY_SIZE_DEFAULT;
+                       *keyAlgStr = "RSA";
+                       break;
+               case ALG_DSA:
+                       *keyAlg = CSSM_ALGID_DSA;
+                       *signAlg = CSSM_ALGID_SHA1WithDSA;
+                       *keySizeInBits = CSP_DSA_KEY_SIZE_DEFAULT;
+                       *keyAlgStr = "DSA";
+                       break;
+               case ALG_FEE:
+                       *keyAlg = CSSM_ALGID_FEE;
+                       *signAlg = CSSM_ALGID_SHA1WithECDSA;
+                       *encrAlg = CSSM_ALGID_FEEDEXP;
+                       *keySizeInBits = CSP_FEE_KEY_SIZE_DEFAULT;
+                       *keyAlgStr = "FEE";
+                       break;
+               case ALG_ECDSA:
+                       *keyAlg = CSSM_ALGID_ECDSA;
+                       *signAlg = CSSM_ALGID_SHA1WithECDSA;
+                       *keySizeInBits = CSP_ECDSA_KEY_SIZE_DEFAULT;
+                       *keyAlgStr = "ECDSA";
+                       break;
+               default:
+                       printf("***BRRZAP! privAlgToCssm needs work\n");
+                       exit(1);
+       }
+       return;
+}
+
+int main(int argc, char **argv)
+{
+       int                                     arg;
+       char                            *argp;
+       CSSM_CSP_HANDLE         cspHand;
+       CSSM_ALGORITHMS         keyAlg;                 // CSSM_ALGID_xxx of the key
+       CSSM_ALGORITHMS         signAlg;                // CSSM_ALGID_xxx of the associated signing op
+       CSSM_ALGORITHMS         encrAlg;                // CSSM_ALGID_xxx of the associated encrypt op
+       privAlg                         palg;
+       uint32                          keySizeInBits;
+       int                                     rtn;
+       int                                     i;
+       const char                      *keyAlgStr;
+       
+       /*
+        * User-spec'd params
+        */
+       CSSM_BOOL       quiet = CSSM_FALSE;
+       CSSM_BOOL       doSym = CSSM_TRUE;
+       CSSM_BOOL       doAsym = CSSM_TRUE;
+       CSSM_BOOL       bareCsp = CSSM_TRUE;
+       
+       for(arg=1; arg<argc; arg++) {
+               argp = argv[arg];
+               switch(argp[0]) {
+                   case 'q':
+                       quiet = CSSM_TRUE;
+                               break;
+                   case 's':
+                       doAsym = CSSM_FALSE;
+                               break;
+                   case 'a':
+                       doSym = CSSM_FALSE;
+                               break;
+                   case 'D':
+                       bareCsp = CSSM_FALSE;
+                               break;
+                   case 'h':
+                   default:
+                               usage(argv);
+               }
+       }
+       cspHand = cspDlDbStartup(bareCsp, NULL);
+       if(cspHand == 0) {
+               exit(1);
+       }
+       printf("Starting badattr; args: ");
+       for(i=1; i<argc; i++) {
+               printf("%s ", argv[i]);
+       }
+       printf("\n");
+       
+       if(doSym) {
+               for(palg=SYM_FIRST; palg<=SYM_LAST; palg++) {
+                       privAlgToCssm(palg, &keyAlg, &signAlg, &encrAlg, &keySizeInBits, &keyAlgStr);
+                       if(!quiet) {
+                               printf("   ...alg %s\n", keyAlgStr);
+                       }
+                       rtn = symAttrTest(cspHand, keyAlg, keyAlgStr, keySizeInBits, bareCsp, 
+                                       quiet);
+                       if(rtn) {
+                               goto abort;
+                       }
+                       rtn = symNullWrapTest(cspHand, keyAlg, keyAlgStr, keySizeInBits, quiet);
+                       if(rtn) {
+                               goto abort;
+                       }
+                       rtn = symBadWrapTest(cspHand, keyAlg, keyAlgStr, keySizeInBits, quiet);
+                       if(rtn) {
+                               goto abort;
+                       }
+                       rtn = symUsageTest(cspHand, keyAlg, keyAlgStr, encrAlg, signAlg, 
+                                       keySizeInBits, quiet);
+                       if(rtn) {
+                               goto abort;
+                       }
+                       if(bareCsp || CSPDL_MUNGE_HEADER_CHECK) {
+                               rtn = symHeaderTest(cspHand, keyAlg, keyAlgStr, encrAlg, signAlg, 
+                                               keySizeInBits, quiet);
+                               if(rtn) {
+                                       goto abort;
+                               }
+                       }
+                       else if(!quiet) {
+                               printf("      ...SKIPPING munged ref key header test\n");
+                       }
+               }
+       }
+       
+       if(doAsym) {
+               for(palg=ASYM_FIRST; palg<=ASYM_LAST; palg++) {
+                       privAlgToCssm(palg, &keyAlg, &signAlg, &encrAlg, &keySizeInBits, 
+                               &keyAlgStr);
+                       if(!quiet) {
+                               printf("   ...alg %s\n", keyAlgStr);
+                       }
+                       rtn = asymAttrTest(cspHand, keyAlg, keyAlgStr, keySizeInBits, 
+                               bareCsp, quiet);
+                       if(rtn) {
+                               goto abort;
+                       }
+                       rtn = asymNullWrapTest(cspHand, keyAlg, keyAlgStr, keySizeInBits, quiet);
+                       if(rtn) {
+                               goto abort;
+                       }
+                       rtn = asymBadWrapTest(cspHand, keyAlg, keyAlgStr, keySizeInBits, quiet);
+                       if(rtn) {
+                               goto abort;
+                       }
+                       if(bareCsp || CSPDL_MUNGE_HEADER_CHECK) {
+                               rtn = asymHeaderTest(cspHand, keyAlg, keyAlgStr, encrAlg, signAlg, 
+                                               keySizeInBits, quiet);
+                               if(rtn) {
+                                       goto abort;
+                               }
+                       }
+                       else if(!quiet) {
+                               printf("      ...SKIPPING munged ref key header test\n");
+                       }
+               }
+       }
+abort:
+       cspShutdown(cspHand, bareCsp);
+       if((rtn == 0) && !quiet) {
+               printf("%s complete\n", argv[0]);
+       }
+       return rtn;
+}
+