--- /dev/null
+/* Copyright (c) 1998,2003-2005,2008 Apple Inc.
+ *
+ * wrapTest.c - wrap/unwrap exerciser.
+ *
+ * Revision History
+ * ----------------
+ * 4 May 2000 Doug Mitchell
+ * Ported to X/CDSA2.
+ * 6 Aug 1998 Doug Mitchell at Apple
+ * Created.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <Security/cssm.h>
+#include "cspwrap.h"
+#include "common.h"
+#include "cspdlTesting.h"
+
+/*
+ * Currently the CSP can use wrapping keys flagged exclusively for wrapping
+ * (CSSM_KEYUSE_{WRAP,UNWRAP} for the actual wrap sinceĆthe wrp/unwrap op is
+ * done with an encrypt/decrypt op. The WrapKey op doesn't even see the
+ * wrapping key - it's in the context we pass it. Thus for now wrap/unwrap
+ * keys have to be marked with CSSM_KEYUSE_ANY.
+ */
+#define WRAP_USAGE_ANY 0
+
+/*
+ * When false, the CMS wrap algorithm can't deal with RSA encryption - we
+ * have to encrypt something twice with the same key. An impossibility with
+ * BSAFE-based RSA encryption because the output of the first encrypt is
+ * the size of the key modulus, and you can't encrypt something that big
+ * with that key.
+ * This is not a limitation with openssl-based RSA.
+ */
+#define WRAP_WITH_RSA 1
+
+/*
+ * When false, can't wrap with RC4 because the RC4 context is stateful
+ * but doesn't get reinit'd for the second CMS encrypt.
+ */
+#define WRAP_WITH_RC4 1
+
+/*
+ * Temporary hack to use CSSM_KEYBLOB_WRAPPED_FORMAT_{PKCS7,PKCS8}, which
+ * are no longer supported as of 7/28/00
+ */
+#define PKCS7_FORMAT_ENABLE 1 // for wrapping symmetric keys
+#define PKCS8_FORMAT_ENABLE 1 // for wrapping private keys
+
+
+#define ENCR_LABEL "encrKey"
+#define ENCR_LABEL_LEN (strlen(ENCR_LABEL))
+#define WRAP_LABEL "wrapKey"
+#define WRAP_LABEL_LEN (strlen(WRAP_LABEL))
+#define LOOPS_DEF 10
+#define MAX_PTEXT_SIZE 100
+#define LOOP_PAUSE 100
+#define MAX_DESC_DATA_SIZE 16
+
+/*
+ * Enumerate algorithms our way to allow loop interations.
+ */
+typedef unsigned PrivAlg;
+enum {
+ ALG_DES = 1,
+ ALG_3DES,
+ ALG_RC2,
+ ALG_RC4,
+ ALG_RSA,
+ ALG_NULL,
+ ALG_FEEDEXP,
+ ALG_ASC,
+ ALG_AES
+};
+
+#define ALG_MIN ALG_DES
+#define ALG_MAX_WRAP ALG_AES
+#define ALG_MAX_ENCR ALG_AES
+
+static void usage(char **argv)
+{
+ printf("usage: %s [options]\n", argv[0]);
+ printf(" Options:\n");
+ printf(" w=wrapAlg (d=DES, 3=3DES, f=FEEDEXP, r=RSA, A=ASC, 4=RC4, "
+ "a=AES, n=null)\n");
+ printf(" e=encrAlg (d=DES, 3=3DES, f=FEEDEXP, r=RSA, A=ASC, 4=RC4, "
+ "a=AES)\n");
+ printf(" l=loops (default=%d; 0=forever)\n", LOOPS_DEF);
+ printf(" r (ref keys only)\n");
+ printf(" p(ause every loop)\n");
+ printf(" D (CSP/DL; default = bare CSP)\n");
+ printf(" v(erbose)\n");
+ printf(" k (quick; small keys)\n");
+ printf(" h(elp)\n");
+ exit(1);
+}
+
+/* wrapped format to string */
+static const char *formatString(CSSM_KEYBLOB_FORMAT format)
+{
+ static char noform[100];
+
+ switch(format) {
+ case CSSM_KEYBLOB_WRAPPED_FORMAT_NONE:
+ return "NONE (default)";
+ case CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7:
+ return "PKCS7";
+ case CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8:
+ return "PKCS8";
+ case CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM:
+ return "APPLE_CUSTOM";
+ default:
+ sprintf(noform, "***UNKNOWN (%u)***", (unsigned)format);
+ return noform;
+ }
+}
+
+static int vfyWrapHeader(
+ const CSSM_KEYHEADER *srcHdr,
+ const CSSM_KEYHEADER *dstHdr,
+ CSSM_KEYBLOB_TYPE expectBlob,
+ const char *op,
+ CSSM_BOOL bareCsp,
+ int quiet)
+{
+ if(dstHdr->BlobType != expectBlob) {
+ printf("***%s.BlobType error: expect %u got %u\n",
+ op, (unsigned)expectBlob, (unsigned)dstHdr->BlobType);
+ if(testError(quiet)) {
+ return 1;
+ }
+ }
+ if(srcHdr->KeyClass != dstHdr->KeyClass) {
+ printf("***%s.KeyClass error: expect %u got %u\n",
+ op, (unsigned)srcHdr->KeyClass, (unsigned)dstHdr->KeyClass);
+ if(testError(quiet)) {
+ return 1;
+ }
+ }
+ if(srcHdr->AlgorithmId != dstHdr->AlgorithmId) {
+ printf("***%s.AlgorithmId error: expect %u got %u\n",
+ op, (unsigned)srcHdr->AlgorithmId, (unsigned)dstHdr->AlgorithmId);
+ if(testError(quiet)) {
+ return 1;
+ }
+ }
+ if(srcHdr->KeyUsage != dstHdr->KeyUsage) {
+ printf("***%s.KeyUsage error: expect 0x%x got 0x%x\n",
+ op, (unsigned)srcHdr->KeyUsage, (unsigned)dstHdr->KeyUsage);
+ if(testError(quiet)) {
+ return 1;
+ }
+ }
+ if(bareCsp) {
+ /* GUIDs must match */
+ if(memcmp(&srcHdr->CspId, &dstHdr->CspId, sizeof(CSSM_GUID))) {
+ printf("***%s.CspId mismatch\n", op);
+ if(testError(quiet)) {
+ return 1;
+ }
+ }
+ }
+ else {
+ /* CSPDL - GUIDs do NOT match - ref keys are in the CSPDL's domain;
+ * wrapped keys are in the bare CSP's domain. */
+ if(!memcmp(&srcHdr->CspId, &dstHdr->CspId, sizeof(CSSM_GUID))) {
+ printf("***Unexpected %s.CspId compare\n", op);
+ if(testError(quiet)) {
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+#define UNWRAPPED_LABEL "unwrapped thing"
+#define SHOW_WRAP_FORMAT 0
+
+/* not all algs need this */
+CSSM_DATA initVector = {16, (uint8 *)"SomeReallyStrangeInitVect"};
+
+static int doTest(CSSM_CSP_HANDLE cspHand,
+ CSSM_KEY_PTR encrKey,
+ CSSM_BOOL wrapEncrKey, // wrap encrKey before using
+ CSSM_KEY_PTR decrKey, // we wrap this one
+ CSSM_KEY_PTR wrappingKey, // ...using this key
+ CSSM_KEY_PTR unwrappingKey,
+ CSSM_ALGORITHMS wrapAlg,
+ CSSM_ENCRYPT_MODE wrapMode,
+ CSSM_KEYBLOB_FORMAT wrapFormat, // NONE, PKCS7, PKCS8, APPLE_CUSTOM
+ CSSM_KEYBLOB_FORMAT expectFormat, // PKCS7, PKCS8, APPLE_CUSTOM
+ CSSM_PADDING wrapPad,
+ uint32 wrapIvSize,
+ CSSM_ALGORITHMS encrAlg,
+ CSSM_ENCRYPT_MODE encrMode,
+ CSSM_PADDING encrPad,
+ uint32 encrIvSize,
+ uint32 effectiveKeySizeInBits, // for encr/decr - 0 means none specified
+ CSSM_DATA_PTR ptext,
+ CSSM_DATA_PTR descData,
+ CSSM_BOOL quiet,
+ CSSM_BOOL bareCsp)
+{
+ CSSM_DATA ctext;
+ CSSM_DATA rptext;
+ CSSM_KEY wrappedDecrKey;
+ CSSM_KEY unwrappedDecrKey;
+ CSSM_KEY wrappedEncrKey;
+ CSSM_RETURN crtn;
+ CSSM_KEY_PTR actualEncrKey;
+ uint32 maxPtextSize = MAX_PTEXT_SIZE;
+ CSSM_DATA outDescData1 = {0, NULL}; // for encr key
+ CSSM_DATA outDescData2 = {0, NULL}; // for decr key, must match descData
+ CSSM_DATA nullInitVect = {0, NULL}; // for custom unwrap
+ CSSM_DATA_PTR wrapIvp;
+ CSSM_DATA_PTR encrIvp;
+
+ /* Hack to deal with RSA's max encrypt size */
+ #if 0
+ /* no more */
+ if(encrAlg == CSSM_ALGID_RSA) {
+ uint32 keySizeBytes = encrKey->KeyHeader.LogicalKeySizeInBits / 8;
+ maxPtextSize = keySizeBytes - 11;
+ if(maxPtextSize > MAX_PTEXT_SIZE) {
+ maxPtextSize = MAX_PTEXT_SIZE;
+ }
+ }
+ else {
+ maxPtextSize = MAX_PTEXT_SIZE;
+ }
+ #endif
+ simpleGenData(ptext, 1, maxPtextSize);
+
+ /*
+ * Optionaly wrap/unwrap encrKey. If encrKey is a ref key, do a
+ * NULL wrap. If encrKey is a raw key, do a NULL unwrap.
+ */
+ if(wrapEncrKey) {
+ CSSM_KEYBLOB_TYPE expectBlob;
+
+ if(encrKey->KeyHeader.BlobType == CSSM_KEYBLOB_REFERENCE) {
+ crtn = cspWrapKey(cspHand,
+ encrKey,
+ NULL, // wrappingKey
+ CSSM_ALGID_NONE,
+ CSSM_ALGMODE_NONE,
+ wrapFormat,
+ CSSM_PADDING_NONE,
+ NULL, // iv
+ descData,
+ &wrappedEncrKey);
+ expectBlob = CSSM_KEYBLOB_RAW;
+ }
+ else {
+ crtn = cspUnwrapKey(cspHand,
+ encrKey,
+ NULL, // unwrappingKey
+ CSSM_ALGID_NONE,
+ CSSM_ALGMODE_NONE,
+ CSSM_PADDING_NONE,
+ NULL, // iv
+ &wrappedEncrKey,
+ &outDescData1,
+ WRAP_LABEL,
+ WRAP_LABEL_LEN);
+ expectBlob = CSSM_KEYBLOB_REFERENCE;
+ }
+ if(crtn) {
+ return testError(quiet);
+ }
+ if(vfyWrapHeader(&encrKey->KeyHeader,
+ &wrappedEncrKey.KeyHeader,
+ expectBlob,
+ "wrappedEncrKey",
+ bareCsp,
+ quiet)) {
+ return 1;
+ }
+ actualEncrKey = &wrappedEncrKey;
+ }
+ else {
+ actualEncrKey = encrKey;
+ }
+ /* encrypt using actualEncrKey ==> ctext */
+ ctext.Data = NULL;
+ ctext.Length = 0;
+ if(encrIvSize) {
+ initVector.Length = encrIvSize;
+ encrIvp = &initVector;
+ }
+ else {
+ encrIvp = NULL;
+ }
+ crtn = cspEncrypt(cspHand,
+ encrAlg,
+ encrMode,
+ encrPad,
+ actualEncrKey,
+ NULL, // no 2nd key
+ effectiveKeySizeInBits,
+ 0, // rounds
+ encrIvp,
+ ptext,
+ &ctext,
+ CSSM_TRUE); // mallocCtext
+ if(crtn) {
+ return testError(quiet);
+ }
+ /* wrap decrKey using wrappingKey ==> wrappedDecrKey */
+ /* Note that APPLE_CUSTOM wrap alg REQUIRES an 8-byte IV */
+ if(expectFormat == CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM) {
+ initVector.Length = 8;
+ }
+ else {
+ initVector.Length = wrapIvSize;
+ }
+ crtn = cspWrapKey(cspHand,
+ decrKey,
+ wrappingKey,
+ wrapAlg,
+ wrapMode,
+ wrapFormat,
+ wrapPad,
+ &initVector,
+ descData,
+ &wrappedDecrKey);
+ if(crtn) {
+ return testError(quiet);
+ }
+ if(wrapAlg != CSSM_ALGID_NONE) {
+ if(wrappedDecrKey.KeyHeader.Format != expectFormat) {
+ printf("***Wrap format mismatch expect %s got %s\n",
+ formatString(wrappedDecrKey.KeyHeader.Format),
+ formatString(expectFormat));
+ if(testError(quiet)) {
+ return 1;
+ }
+ }
+ }
+
+ if(vfyWrapHeader(&decrKey->KeyHeader,
+ &wrappedDecrKey.KeyHeader,
+ (wrapAlg == CSSM_ALGID_NONE) ? CSSM_KEYBLOB_RAW : CSSM_KEYBLOB_WRAPPED,
+ "wrappedDecrKey",
+ bareCsp,
+ quiet)) {
+ return 1;
+ }
+
+ if(wrappedDecrKey.KeyHeader.Format == CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM) {
+ /* special case - no IV needed - test it */
+ wrapIvp = &nullInitVect;
+ }
+ else {
+ wrapIvp = &initVector;
+ initVector.Length = wrapIvSize;
+ }
+
+ /* unwrap wrappedDecrKey using unwrappingKey ==> unwrappedDecrKey; */
+ crtn = cspUnwrapKey(cspHand,
+ &wrappedDecrKey,
+ unwrappingKey,
+ wrapAlg,
+ wrapMode,
+ wrapPad,
+ wrapIvp,
+ &unwrappedDecrKey,
+ &outDescData2,
+ "unwrapped thing",
+ 15);
+ if(crtn) {
+ return testError(quiet);
+ }
+
+ if(vfyWrapHeader(&wrappedDecrKey.KeyHeader,
+ &unwrappedDecrKey.KeyHeader,
+ CSSM_KEYBLOB_REFERENCE,
+ "unwrappedDecrKey",
+ bareCsp,
+ quiet)) {
+ return 1;
+ }
+
+ /* compare descData to outDescData2 */
+ if(descData) {
+ if(descData->Length != outDescData2.Length) {
+ printf("descData length mismatch\n");
+ if(testError(quiet)) {
+ return 1;
+ }
+ }
+ if(memcmp(descData->Data, outDescData2.Data, outDescData2.Length)) {
+ printf("***descDatadata miscompare\n");
+ if(testError(quiet)) {
+ return 1;
+ }
+ }
+ }
+
+ /* decrypt ctext with unwrappedDecrKey ==> rptext; */
+ rptext.Data = NULL;
+ rptext.Length = 0;
+ if(encrIvSize) {
+ initVector.Length = encrIvSize;
+ }
+ crtn = cspDecrypt(cspHand,
+ encrAlg,
+ encrMode,
+ encrPad,
+ &unwrappedDecrKey,
+ NULL, // no 2nd key
+ effectiveKeySizeInBits,
+ 0, // rounds
+ &initVector,
+ &ctext,
+ &rptext,
+ CSSM_TRUE);
+ if(crtn) {
+ return testError(quiet);
+ }
+ /* compare ptext vs. rptext; */
+ if(ptext->Length != rptext.Length) {
+ printf("ptext length mismatch\n");
+ return testError(quiet);
+ }
+ if(memcmp(ptext->Data, rptext.Data, ptext->Length)) {
+ printf("***data miscompare\n");
+ return testError(quiet);
+ }
+ /* free resources */
+ cspFreeKey(cspHand, &wrappedDecrKey);
+ cspFreeKey(cspHand, &unwrappedDecrKey);
+ if(wrapEncrKey) {
+ cspFreeKey(cspHand, actualEncrKey);
+ }
+ CSSM_FREE(ctext.Data);
+ CSSM_FREE(rptext.Data);
+ if(outDescData2.Data != NULL) {
+ CSSM_FREE(outDescData2.Data);
+ }
+ if(outDescData1.Data != NULL) {
+ CSSM_FREE(outDescData1.Data);
+ }
+ return 0;
+}
+
+/*
+ * values associated with a private algorithm (e.g., ALG_DES).
+ */
+typedef enum {
+ WT_Symmetric,
+ WT_Asymmetric,
+ WT_Null
+} wrapType;
+
+typedef struct {
+ uint32 keyGenAlg;
+ wrapType wtype;
+ CSSM_ALGORITHMS encrAlg;
+ CSSM_ENCRYPT_MODE encrMode;
+ CSSM_PADDING encrPad;
+ uint32 ivSize; // in bytes; 0 means no IV
+ const char *algName;
+} AlgInfo;
+
+/*
+ * Convert our private alg to CDSA keygen alg, encr alg, encr mode, pad
+ */
+static void getAlgInfo(PrivAlg privAlg, // e.g., ALG_DES
+ AlgInfo *algInfo)
+{
+ switch(privAlg) {
+ case ALG_DES:
+ algInfo->keyGenAlg = CSSM_ALGID_DES;
+ algInfo->wtype = WT_Symmetric;
+ algInfo->encrAlg = CSSM_ALGID_DES;
+ algInfo->encrMode = CSSM_ALGMODE_CBCPadIV8;
+ algInfo->encrPad = CSSM_PADDING_PKCS5;
+ algInfo->ivSize = 8;
+ algInfo->algName = "DES";
+ break;
+ case ALG_3DES:
+ algInfo->keyGenAlg = CSSM_ALGID_3DES_3KEY;
+ algInfo->wtype = WT_Symmetric;
+ algInfo->encrAlg = CSSM_ALGID_3DES_3KEY_EDE;
+ algInfo->encrMode = CSSM_ALGMODE_CBCPadIV8;
+ algInfo->encrPad = CSSM_PADDING_PKCS5;
+ algInfo->ivSize = 8;
+ algInfo->algName = "3DES";
+ break;
+ case ALG_FEEDEXP:
+ algInfo->keyGenAlg = CSSM_ALGID_FEE;
+ algInfo->wtype = WT_Asymmetric;
+ algInfo->encrAlg = CSSM_ALGID_FEEDEXP;
+ algInfo->encrMode = CSSM_ALGMODE_NONE;
+ algInfo->encrPad = CSSM_PADDING_NONE;
+ algInfo->ivSize = 0;
+ algInfo->algName = "FEEDEXP";
+ break;
+ case ALG_RSA:
+ algInfo->keyGenAlg = CSSM_ALGID_RSA;
+ algInfo->wtype = WT_Asymmetric;
+ algInfo->encrAlg = CSSM_ALGID_RSA;
+ algInfo->encrMode = CSSM_ALGMODE_NONE;
+ algInfo->encrPad = CSSM_PADDING_PKCS1;
+ algInfo->ivSize = 0;
+ algInfo->algName = "RSA";
+ break;
+ case ALG_ASC:
+ algInfo->keyGenAlg = CSSM_ALGID_ASC;
+ algInfo->wtype = WT_Symmetric;
+ algInfo->encrAlg = CSSM_ALGID_ASC;
+ algInfo->encrMode = CSSM_ALGMODE_NONE;
+ algInfo->encrPad = CSSM_PADDING_NONE;
+ algInfo->ivSize = 0;
+ algInfo->algName = "ASC";
+ break;
+ case ALG_RC2:
+ algInfo->keyGenAlg = CSSM_ALGID_RC2;
+ algInfo->wtype = WT_Symmetric;
+ algInfo->encrAlg = CSSM_ALGID_RC2;
+ algInfo->encrMode = CSSM_ALGMODE_CBCPadIV8;
+ algInfo->encrPad = CSSM_PADDING_PKCS5;
+ algInfo->ivSize = 8;
+ algInfo->algName = "RC2";
+ break;
+ case ALG_RC4:
+ algInfo->keyGenAlg = CSSM_ALGID_RC4;
+ algInfo->wtype = WT_Symmetric;
+ algInfo->encrAlg = CSSM_ALGID_RC4;
+ algInfo->encrMode = CSSM_ALGMODE_CBCPadIV8;
+ algInfo->encrPad = CSSM_PADDING_PKCS5;
+ algInfo->ivSize = 0;
+ algInfo->algName = "RC4";
+ break;
+ case ALG_NULL:
+ algInfo->keyGenAlg = CSSM_ALGID_NONE;
+ algInfo->wtype = WT_Null;
+ algInfo->encrAlg = CSSM_ALGID_NONE;
+ algInfo->encrMode = CSSM_ALGMODE_NONE;
+ algInfo->encrPad = CSSM_PADDING_NONE;
+ algInfo->ivSize = 0;
+ algInfo->algName = "Null";
+ break;
+ case ALG_AES:
+ algInfo->keyGenAlg = CSSM_ALGID_AES;
+ algInfo->wtype = WT_Symmetric;
+ algInfo->encrAlg = CSSM_ALGID_AES;
+ algInfo->encrMode = CSSM_ALGMODE_CBCPadIV8;
+ algInfo->encrPad = CSSM_PADDING_PKCS7;
+ algInfo->ivSize = 16;
+ algInfo->algName = "AES";
+ break;
+ default:
+ printf("Bogus privAlg\n");
+ exit(1);
+ }
+ return;
+}
+
+/* argv letter to private alg */
+static PrivAlg letterToAlg(char **argv, char letter)
+{
+ switch(letter) {
+ case 'd': return ALG_DES;
+ case '3': return ALG_3DES;
+ case 'f': return ALG_FEEDEXP;
+ case 'r': return ALG_RSA;
+ case 'A': return ALG_ASC;
+ case '4': return ALG_RC4;
+ case 'a': return ALG_AES;
+ default:
+ usage(argv);
+ return 0;
+ }
+}
+
+/*
+ * Null wrapping of symmetric keys now allowed
+ */
+#define SYMM_NULL_WRAP_ENABLE 1
+
+/* indices into algInfo[] */
+#define AI_WRAP 0
+#define AI_ENCR 1
+
+int main(int argc, char **argv)
+{
+ int arg;
+ char *argp;
+ unsigned loop;
+ CSSM_CSP_HANDLE cspHand;
+ CSSM_RETURN crtn;
+ CSSM_DATA ptext;
+ uint32 encrKeySizeBits; // well aligned
+ uint32 wrapKeySizeBits;
+ uint32 effectiveKeySizeInBits; // for encr, may be odd
+ int rtn = 0;
+ uint32 maxRsaKeySize = 1024;
+ uint32 maxFeeKeySize = 192;
+ CSSM_KEYBLOB_FORMAT wrapFormat; // NONE, PKCS7, PKCS8, APPLE_CUSTOM
+ CSSM_KEYBLOB_FORMAT expectFormat; // PKCS7, PKCS8, APPLE_CUSTOM
+ CSSM_DATA descData = {0, NULL};
+ CSSM_DATA_PTR descDataP;
+
+ /*
+ * key pointers passed to doTest() - for symmetric algs, the pairs
+ * might point to the same key
+ */
+ CSSM_KEY_PTR encrKeyPtr;
+ CSSM_KEY_PTR decrKeyPtr;
+ CSSM_KEY_PTR wrapKeyPtr;
+ CSSM_KEY_PTR unwrapKeyPtr;
+
+ /* persistent asymmetric keys - symm keys are dynamically allocated */
+ CSSM_KEY pubEncrKey;
+ CSSM_KEY privEncrKey;
+ CSSM_KEY pubWrapKey;
+ CSSM_KEY privWrapKey;
+
+ /* we iterate these values thru all possible algs */
+ PrivAlg privEncrAlg; // ALG_xxx
+ PrivAlg privWrapAlg;
+
+ /* two AlgInfo which contain everything we need to know per alg */
+ AlgInfo algInfo[2];
+ AlgInfo *encrInfo;
+ AlgInfo *wrapInfo;
+ CSSM_BOOL wrapEncrKey = CSSM_FALSE; // varies loop-to-loop
+ CSSM_BOOL encrKeyIsRef = CSSM_TRUE; // ditto
+
+ CSSM_BOOL genSeed; // for FEE key gen
+ int i;
+
+ /* user-specified vars */
+ unsigned loops = LOOPS_DEF;
+ CSSM_BOOL pause = CSSM_FALSE;
+ CSSM_BOOL verbose = CSSM_FALSE;
+ PrivAlg minWrapAlg = ALG_MIN;
+ PrivAlg maxWrapAlg = ALG_MAX_WRAP;
+ PrivAlg minEncrAlg = ALG_MIN;
+ PrivAlg maxEncrAlg = ALG_MAX_ENCR;
+ CSSM_BOOL quick = CSSM_FALSE;
+ CSSM_BOOL quiet = CSSM_FALSE;
+ CSSM_BOOL bareCsp = CSSM_TRUE;
+ CSSM_BOOL refKeysOnly = CSSM_FALSE;
+
+ for(arg=1; arg<argc; arg++) {
+ argp = argv[arg];
+ switch(argp[0]) {
+ case 'w':
+ if(argp[2] == 'n') {
+ minWrapAlg = maxWrapAlg = ALG_NULL;
+ }
+ else {
+ minWrapAlg = maxWrapAlg = letterToAlg(argv, argp[2]);
+ }
+ break;
+ case 'e':
+ minEncrAlg = maxEncrAlg = letterToAlg(argv, argp[2]);
+ break;
+ case 'l':
+ loops = atoi(&argp[2]);
+ break;
+ case 'p':
+ pause = CSSM_TRUE;
+ break;
+ case 'v':
+ verbose = CSSM_TRUE;
+ break;
+ case 'D':
+ bareCsp = CSSM_FALSE;
+ #if CSPDL_ALL_KEYS_ARE_REF
+ refKeysOnly = CSSM_TRUE;
+ #endif
+ break;
+ case 'r':
+ refKeysOnly = CSSM_TRUE;
+ break;
+ case 'q':
+ quiet = CSSM_TRUE;
+ break;
+ case 'k':
+ quick = CSSM_TRUE;
+ maxRsaKeySize = 512;
+ maxFeeKeySize = 127;
+ break;
+ default:
+ usage(argv);
+ }
+ }
+ cspHand = cspDlDbStartup(bareCsp, NULL);
+ if(cspHand == 0) {
+ exit(1);
+ }
+ wrapInfo = &algInfo[AI_WRAP];
+ encrInfo = &algInfo[AI_ENCR];
+
+ /* cook up ptext, descData */
+ ptext.Data = (uint8 *)CSSM_MALLOC(MAX_PTEXT_SIZE);
+ descData.Data = (uint8 *)CSSM_MALLOC(MAX_DESC_DATA_SIZE);
+
+ printf("Starting wrapTest; args: ");
+ for(i=1; i<argc; i++) {
+ printf("%s ", argv[i]);
+ }
+ printf("\n");
+
+ for(loop=0; loop<loops; loop++) {
+ if(!quiet) {
+ printf("...loop %d\n", loop);
+ }
+ if(pause) {
+ fpurge(stdin);
+ printf("Hit CR to proceed: ");
+ getchar();
+ }
+
+ /* iterate thru all encryption algs */
+ for(privEncrAlg=minEncrAlg; privEncrAlg<=maxEncrAlg; privEncrAlg++) {
+ /* handle disabled algs */
+ switch(privEncrAlg) {
+ case ALG_NULL: /* just skip this one, it's just for wrap */
+ continue;
+ default:
+ break;
+ }
+
+ /* generate key(s) to be wrapped */
+ getAlgInfo(privEncrAlg, encrInfo);
+ effectiveKeySizeInBits = randKeySizeBits(encrInfo->keyGenAlg, OT_Encrypt);
+ if(!refKeysOnly) {
+ encrKeyIsRef = (loop & 2) ? CSSM_TRUE : CSSM_FALSE;
+ }
+
+ switch(encrInfo->wtype) {
+ case WT_Symmetric:
+ /* round up to even byte */
+ encrKeySizeBits = (effectiveKeySizeInBits + 7) & ~7;
+ if(encrKeySizeBits == effectiveKeySizeInBits) {
+ effectiveKeySizeInBits = 0;
+ }
+ encrKeyPtr = decrKeyPtr = cspGenSymKey(cspHand,
+ encrInfo->keyGenAlg,
+ ENCR_LABEL,
+ ENCR_LABEL_LEN,
+ CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT,
+ encrKeySizeBits,
+ encrKeyIsRef);
+ if(encrKeyPtr == NULL) {
+ rtn = 1;
+ goto testDone;
+ }
+ #if SYMM_NULL_WRAP_ENABLE
+ /* wrapEncrKey every other loop */
+ if(!refKeysOnly) {
+ wrapEncrKey = (loop & 1) ? CSSM_TRUE : CSSM_FALSE;
+ }
+ #else
+ wrapEncrKey = CSSM_FALSE;
+ #endif /* SYMM_NULL_WRAP_ENABLE */
+ break;
+ case WT_Asymmetric:
+ /* handle alg-specific cases */
+ genSeed = CSSM_FALSE;
+ switch(privEncrAlg) {
+ case ALG_RSA:
+ if(effectiveKeySizeInBits > maxRsaKeySize) {
+ effectiveKeySizeInBits = maxRsaKeySize;
+ }
+ break;
+ case ALG_FEEDEXP:
+ if(effectiveKeySizeInBits > maxFeeKeySize) {
+ effectiveKeySizeInBits = maxFeeKeySize;
+ }
+ if(loop & 4) {
+ genSeed = CSSM_TRUE;
+ }
+ break;
+ default:
+ break;
+ }
+ encrKeySizeBits = effectiveKeySizeInBits;
+ effectiveKeySizeInBits = 0; // i.e., not specified
+ crtn = cspGenKeyPair(cspHand,
+ encrInfo->keyGenAlg,
+ ENCR_LABEL,
+ ENCR_LABEL_LEN,
+ encrKeySizeBits,
+ &pubEncrKey,
+ encrKeyIsRef, // pubIsRef
+ CSSM_KEYUSE_ENCRYPT,
+ CSSM_KEYBLOB_RAW_FORMAT_NONE,
+ &privEncrKey,
+ CSSM_TRUE, // privIsRef
+ CSSM_KEYUSE_DECRYPT,
+ CSSM_KEYBLOB_RAW_FORMAT_NONE,
+ genSeed);
+ if(crtn) {
+ rtn = testError(quiet);
+ goto testDone;
+ }
+ encrKeyPtr = &pubEncrKey;
+ decrKeyPtr = &privEncrKey;
+ /* wrapEncrKey every other loop */
+ if(!refKeysOnly) {
+ wrapEncrKey = (loop & 1) ? CSSM_TRUE : CSSM_FALSE;
+ }
+ break;
+ case WT_Null:
+ printf("***BRRZAP: can't do null encrypt\n");
+ goto testDone;
+ }
+ if(verbose) {
+ printf(" ...encrAlg %s wrapEncrKey %d encrKeyIsRef %d size %u "
+ "bits effectSize %u\n",
+ encrInfo->algName, (int)wrapEncrKey, (int)encrKeyIsRef,
+ (unsigned)encrKeySizeBits, (unsigned)effectiveKeySizeInBits);
+ }
+ /* iterate thru all wrap algs */
+ for(privWrapAlg=minWrapAlg; privWrapAlg<=maxWrapAlg; privWrapAlg++) {
+ /* handle disabled algs */
+ if((privWrapAlg == ALG_AES) && (privEncrAlg == ALG_FEEDEXP)) {
+ /*
+ * Can't do it. FEED can't do PKCS8 because it doesn't
+ * support PKCS8 private key format, and AES can't
+ * do APPLE_CUSTOM because AES needs a 16-byte IV.
+ */
+ continue;
+ }
+ /* any other restrictions/ */
+
+ /* generate wrapping key(s) */
+ getAlgInfo(privWrapAlg, wrapInfo);
+ switch(wrapInfo->wtype) {
+ case WT_Symmetric:
+ /* note we can't do odd-size wrapping keys */
+ wrapKeySizeBits = randKeySizeBits(wrapInfo->keyGenAlg,
+ OT_KeyExch);
+ wrapKeySizeBits &= ~7;
+ wrapKeyPtr = unwrapKeyPtr = cspGenSymKey(cspHand,
+ wrapInfo->keyGenAlg,
+ WRAP_LABEL,
+ WRAP_LABEL_LEN,
+ WRAP_USAGE_ANY ? CSSM_KEYUSE_ANY :
+ CSSM_KEYUSE_WRAP | CSSM_KEYUSE_UNWRAP,
+ wrapKeySizeBits,
+ CSSM_TRUE);
+ if(wrapKeyPtr == NULL) {
+ rtn = 1;
+ goto testDone;
+ }
+ break;
+ case WT_Asymmetric:
+ wrapKeySizeBits = randKeySizeBits(wrapInfo->keyGenAlg,
+ OT_KeyExch);
+ genSeed = CSSM_FALSE;
+ switch(privWrapAlg) {
+ case ALG_RSA:
+ if(wrapKeySizeBits > maxRsaKeySize) {
+ wrapKeySizeBits = maxRsaKeySize;
+ }
+ break;
+ case ALG_FEEDEXP:
+ if(wrapKeySizeBits > maxFeeKeySize) {
+ wrapKeySizeBits = maxFeeKeySize;
+ }
+ if(loop & 2) {
+ genSeed = CSSM_TRUE;
+ }
+ break;
+ default:
+ break;
+ }
+ crtn = cspGenKeyPair(cspHand,
+ wrapInfo->keyGenAlg,
+ WRAP_LABEL,
+ WRAP_LABEL_LEN,
+ wrapKeySizeBits,
+ &pubWrapKey,
+ CSSM_TRUE, // pubIsRef
+ WRAP_USAGE_ANY ? CSSM_KEYUSE_ANY : CSSM_KEYUSE_WRAP,
+ CSSM_KEYBLOB_RAW_FORMAT_NONE,
+ &privWrapKey,
+ CSSM_TRUE, // privIsRef
+ WRAP_USAGE_ANY ? CSSM_KEYUSE_ANY : CSSM_KEYUSE_UNWRAP,
+ CSSM_KEYBLOB_RAW_FORMAT_NONE,
+ genSeed);
+ if(crtn) {
+ rtn = testError(quiet);
+ goto testDone;
+ }
+ wrapKeyPtr = &pubWrapKey;
+ unwrapKeyPtr = &privWrapKey;
+ break;
+ case WT_Null:
+ #if !SYMM_NULL_WRAP_ENABLE
+ if(encrInfo->wtype == WT_Symmetric) {
+ /* can't do null wrap of symmetric key */
+ continue;
+ }
+ #endif
+ wrapKeySizeBits = 0;
+ wrapKeyPtr = NULL;
+ unwrapKeyPtr = NULL;
+ break;
+ }
+
+ /* special case for 3DES/3DES */
+ #if 0
+ if((wrapKeyPtr != NULL) &&
+ (wrapKeyPtr->KeyHeader.AlgorithmId == CSSM_ALGID_3DES_3KEY) &&
+ (decrKeyPtr->KeyHeader.AlgorithmId == CSSM_ALGID_3DES_3KEY)) {
+ isAppleCustom = CSSM_TRUE;
+ }
+ else {
+ isAppleCustom = CSSM_FALSE;
+ }
+ #endif
+
+ /* cook up a wrapFormat - every other loop use default, others
+ * specify a reasonable one */
+ if(wrapInfo->wtype == WT_Null) {
+ wrapFormat = expectFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_NONE;
+ }
+ else if((loop & 1)) {
+ /*
+ * FORMAT_NONE - default - figure out expected format;
+ * this has to track CSP behavior
+ */
+ wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_NONE;
+ switch(encrInfo->wtype) {
+ case WT_Symmetric:
+ expectFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7;
+ break;
+ case WT_Asymmetric:
+ if(privEncrAlg == ALG_FEEDEXP) {
+ expectFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM;
+ }
+ else {
+ expectFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8;
+ }
+ break;
+ default:
+ /* NULL encr not done */
+ printf("**GAK! Internal error\n");
+ }
+ }
+ else {
+ /* pick a good explicit one - this encapsulates the
+ * range of legal wrap formats per wrap/encrypt alg */
+ int die = loop & 2;
+ switch(encrInfo->wtype) {
+ case WT_Symmetric:
+ if(privWrapAlg == ALG_AES) {
+ /* can't do APPLE_CUSTOM - 16 byte IV */
+ wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7;
+ }
+ else if(die) {
+ wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7;
+ }
+ else {
+ wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM;
+ }
+ break;
+ case WT_Asymmetric:
+ /* Can't wrap FEE key with AES no way, no how -
+ * this is detected at the top of the privWrapAlg
+ * loop
+ */
+ if(privEncrAlg == ALG_FEEDEXP) {
+ /* FEE doesn't do PKCS8 private key format */
+ wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM;
+ }
+ else if(die) {
+ wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8;
+ }
+ else if(privWrapAlg == ALG_AES) {
+ /* AES can't do APPLE_CUSTOM - 16 byte IV */
+ wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8;
+ }
+ else {
+ wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM;
+ }
+ break;
+ default:
+ /* NULL encr not done */
+ printf("***GAK! Internal error\n");
+ exit(1);
+ }
+ expectFormat = wrapFormat;
+ }
+
+ /*
+ * If wrapping with apple custom - either by default or
+ * explicitly - generate some descriptive data.
+ */
+ if(expectFormat == CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM) {
+ simpleGenData(&descData, 1, MAX_DESC_DATA_SIZE);
+ descDataP = &descData;
+ }
+ else {
+ descDataP = NULL;
+ }
+
+ if(verbose) {
+ printf(" ...wrapAlg = %s size %u bits format %s expect %s\n",
+ wrapInfo->algName, (unsigned)wrapKeySizeBits, formatString(wrapFormat),
+ formatString(expectFormat));
+ }
+ /* OK, here we go! */
+ if(doTest(cspHand,
+ encrKeyPtr,
+ wrapEncrKey,
+ decrKeyPtr,
+ wrapKeyPtr,
+ unwrapKeyPtr,
+ wrapInfo->encrAlg,
+ wrapInfo->encrMode,
+ wrapFormat,
+ expectFormat,
+ wrapInfo->encrPad,
+ wrapInfo->ivSize,
+ encrInfo->encrAlg,
+ encrInfo->encrMode,
+ encrInfo->encrPad,
+ encrInfo->ivSize,
+ effectiveKeySizeInBits,
+ &ptext,
+ descDataP,
+ quiet,
+ bareCsp)) {
+ rtn = 1;
+ goto testDone;
+ }
+ /* end of wrap alg loop - free/delete wrap key(s) */
+ switch(wrapInfo->wtype) {
+ case WT_Symmetric:
+ cspFreeKey(cspHand, wrapKeyPtr);
+ /* mallocd by cspGenSymKey */
+ CSSM_FREE(wrapKeyPtr);
+ break;
+ case WT_Asymmetric:
+ cspFreeKey(cspHand, wrapKeyPtr);
+ cspFreeKey(cspHand, unwrapKeyPtr);
+ break;
+ default:
+ break;
+ }
+ } /* for wrapAlg */
+ /* end of encr alg loop - free encr key(s) */
+ cspFreeKey(cspHand, encrKeyPtr);
+ if(encrInfo->wtype == WT_Symmetric) {
+ /* mallocd by cspGenSymKey */
+ CSSM_FREE(decrKeyPtr);
+ }
+ else {
+ cspFreeKey(cspHand, decrKeyPtr);
+ }
+ }
+ }
+testDone:
+ cspShutdown(cspHand, bareCsp);
+ if(pause) {
+ fpurge(stdin);
+ printf("ModuleDetach/Unload complete; hit CR to exit: ");
+ getchar();
+ }
+ if((rtn == 0) && !quiet) {
+ printf("%s test complete\n", argv[0]);
+ }
+ return rtn;
+}