--- /dev/null
+/* Copyright (c) 1997,2003-2006,2008,2010,2013 Apple Inc.
+ *
+ * cspwrap.c - wrappers to simplify access to CDSA
+ *
+ * Revision History
+ * ----------------
+ * 3 May 2000 Doug Mitchell
+ * Ported to X/CDSA2.
+ * 12 Aug 1997 Doug Mitchell at Apple
+ * Created.
+ */
+
+#include <Security/cssmapple.h>
+#include <Security/cssm.h>
+#include "cspwrap.h"
+#include "common.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+/* MCF hack */
+// #include <CarbonCore/MacTypes.h>
+#include <MacTypes.h>
+/* end MCF */
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif /* NULL */
+#ifndef MAX
+#define MAX(a,b) ((a > b) ? a : b)
+#define MIN(a,b) ((a < b) ? a : b)
+#endif
+
+#pragma mark --------- Key Generation ---------
+
+/*
+ * Key generation
+ */
+#define FEE_PRIV_DATA_SIZE 20
+/*
+ * Debug/test only. BsafeCSP only (long since disabled, in Puma).
+ * This results in quicker but less secure RSA key generation.
+ */
+#define RSA_WEAK_KEYS 0
+
+/*
+ * Force bad data in KeyData prior to generating, deriving, or
+ * wrapping key to ensure that the CSP ignores incoming
+ * KeyData.
+ */
+static void setBadKeyData(
+ CSSM_KEY_PTR key)
+{
+ key->KeyData.Data = (uint8 *)0xeaaaeaaa; // bad ptr
+ key->KeyData.Length = 1; // no key can fit here
+}
+
+/*
+ * Generate key pair of arbitrary algorithm.
+ * FEE keys will have random private data.
+ */
+CSSM_RETURN cspGenKeyPair(CSSM_CSP_HANDLE cspHand,
+ uint32 algorithm,
+ const char *keyLabel,
+ unsigned keyLabelLen,
+ uint32 keySize, // in bits
+ CSSM_KEY_PTR pubKey, // mallocd by caller
+ CSSM_BOOL pubIsRef, // true - reference key, false - data
+ uint32 pubKeyUsage, // CSSM_KEYUSE_ENCRYPT, etc.
+ CSSM_KEYBLOB_FORMAT pubFormat, // Optional. Specify 0 or CSSM_KEYBLOB_RAW_FORMAT_NONE
+ // to get the default format.
+ CSSM_KEY_PTR privKey, // mallocd by caller
+ CSSM_BOOL privIsRef, // true - reference key, false - data
+ uint32 privKeyUsage, // CSSM_KEYUSE_DECRYPT, etc.
+ CSSM_KEYBLOB_FORMAT privFormat, // optional 0 ==> default
+ CSSM_BOOL genSeed) // FEE only. True: we generate seed and CSP
+ // will hash it. False: CSP generates random
+ // seed.
+{
+ CSSM_RETURN crtn;
+ CSSM_CC_HANDLE ccHand;
+ CSSM_DATA privData = {0, NULL}; // mallocd for FEE
+ CSSM_CRYPTO_DATA privCData;
+ CSSM_CRYPTO_DATA_PTR privCDataPtr = NULL;
+ CSSM_DATA keyLabelData;
+ uint32 pubAttr;
+ uint32 privAttr;
+ CSSM_RETURN ocrtn = CSSM_OK;
+
+ if(keySize == CSP_KEY_SIZE_DEFAULT) {
+ keySize = cspDefaultKeySize(algorithm);
+ }
+
+ /* pre-context-create algorithm-specific stuff */
+ switch(algorithm) {
+ case CSSM_ALGID_FEE:
+ if(genSeed) {
+ /* cook up random privData */
+ privData.Data = (uint8 *)CSSM_MALLOC(FEE_PRIV_DATA_SIZE);
+ privData.Length = FEE_PRIV_DATA_SIZE;
+ appGetRandomBytes(privData.Data, FEE_PRIV_DATA_SIZE);
+ privCData.Param = privData;
+ privCData.Callback = NULL;
+ privCDataPtr = &privCData;
+ }
+ /* else CSP generates random seed/key */
+ break;
+ case CSSM_ALGID_RSA:
+ break;
+ case CSSM_ALGID_DSA:
+ break;
+ case CSSM_ALGID_ECDSA:
+ break;
+ default:
+ printf("cspGenKeyPair: Unknown algorithm\n");
+ /* but what the hey */
+ privCDataPtr = NULL;
+ break;
+ }
+ keyLabelData.Data = (uint8 *)keyLabel,
+ keyLabelData.Length = keyLabelLen;
+ memset(pubKey, 0, sizeof(CSSM_KEY));
+ memset(privKey, 0, sizeof(CSSM_KEY));
+ setBadKeyData(pubKey);
+ setBadKeyData(privKey);
+
+ crtn = CSSM_CSP_CreateKeyGenContext(cspHand,
+ algorithm,
+ keySize,
+ privCDataPtr, // Seed
+ NULL, // Salt
+ NULL, // StartDate
+ NULL, // EndDate
+ NULL, // Params
+ &ccHand);
+ if(crtn) {
+ printError("CSSM_CSP_CreateKeyGenContext", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+ /* cook up attribute bits */
+ if(pubIsRef) {
+ pubAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE;
+ }
+ else {
+ pubAttr = CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE;
+ }
+ if(privIsRef) {
+ privAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE;
+ }
+ else {
+ privAttr = CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE;
+ }
+
+ /* post-context-create algorithm-specific stuff */
+ switch(algorithm) {
+ case CSSM_ALGID_RSA:
+
+ #if RSA_WEAK_KEYS
+ {
+ /* for testing, speed up key gen by using the
+ * undocumented "CUSTOM" key gen mode. This
+ * results in the CSP using AI_RsaKeyGen instead of
+ * AI_RSAStrongKeyGen.
+ */
+ crtn = AddContextAttribute(ccHand,
+ CSSM_ATTRIBUTE_MODE,
+ sizeof(uint32),
+ CAT_Uint32,
+ NULL,
+ CSSM_ALGMODE_CUSTOM);
+ if(crtn) {
+ printError("CSSM_UpdateContextAttributes", crtn);
+ return crtn;
+ }
+ }
+ #endif // RSA_WEAK_KEYS
+ 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,
+ keySize, &dummy);
+ if(crtn) {
+ printError("CSSM_GenerateAlgorithmParams", crtn);
+ return crtn;
+ }
+ appFreeCssmData(&dummy, CSSM_FALSE);
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* optional format specifiers */
+ if(!pubIsRef && (pubFormat != CSSM_KEYBLOB_RAW_FORMAT_NONE)) {
+ crtn = AddContextAttribute(ccHand,
+ CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT,
+ sizeof(uint32),
+ CAT_Uint32,
+ NULL,
+ pubFormat);
+ if(crtn) {
+ printError("AddContextAttribute(CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT)", crtn);
+ return crtn;
+ }
+ }
+ if(!privIsRef && (privFormat != CSSM_KEYBLOB_RAW_FORMAT_NONE)) {
+ crtn = AddContextAttribute(ccHand,
+ CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT,
+ sizeof(uint32), // currently sizeof CSSM_DATA
+ CAT_Uint32,
+ NULL,
+ privFormat);
+ if(crtn) {
+ printError("AddContextAttribute(CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT)", crtn);
+ return crtn;
+ }
+ }
+ crtn = CSSM_GenerateKeyPair(ccHand,
+ pubKeyUsage,
+ pubAttr,
+ &keyLabelData,
+ pubKey,
+ privKeyUsage,
+ privAttr,
+ &keyLabelData, // same labels
+ NULL, // CredAndAclEntry
+ privKey);
+ if(crtn) {
+ printError("CSSM_GenerateKeyPair", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+ /* basic checks...*/
+ if(privIsRef) {
+ if(privKey->KeyHeader.BlobType != CSSM_KEYBLOB_REFERENCE) {
+ printf("privKey blob type: exp %u got %u\n",
+ CSSM_KEYBLOB_REFERENCE, (unsigned)privKey->KeyHeader.BlobType);
+ ocrtn = CSSM_ERRCODE_INTERNAL_ERROR;
+ goto abort;
+ }
+ }
+ else {
+ switch(privKey->KeyHeader.BlobType) {
+ case CSSM_KEYBLOB_RAW:
+ break;
+ default:
+ printf("privKey blob type: exp raw, got %u\n",
+ (unsigned)privKey->KeyHeader.BlobType);
+ ocrtn = CSSM_ERRCODE_INTERNAL_ERROR;
+ goto abort;
+ }
+ }
+ if(pubIsRef) {
+ if(pubKey->KeyHeader.BlobType != CSSM_KEYBLOB_REFERENCE) {
+ printf("pubKey blob type: exp %u got %u\n",
+ CSSM_KEYBLOB_REFERENCE, (unsigned)pubKey->KeyHeader.BlobType);
+ ocrtn = CSSM_ERRCODE_INTERNAL_ERROR;
+ goto abort;
+ }
+ }
+ else {
+ switch(pubKey->KeyHeader.BlobType) {
+ case CSSM_KEYBLOB_RAW:
+ break;
+ default:
+ printf("pubKey blob type: exp raw or raw_berder, got %u\n",
+ (unsigned)pubKey->KeyHeader.BlobType);
+ ocrtn = CSSM_ERRCODE_INTERNAL_ERROR;
+ goto abort;
+ }
+ }
+abort:
+ if(ccHand != 0) {
+ crtn = CSSM_DeleteContext(ccHand);
+ if(crtn) {
+ printError("CSSM_DeleteContext", crtn);
+ ocrtn = CSSM_ERRCODE_INTERNAL_ERROR;
+ }
+ }
+ if(privData.Data != NULL) {
+ CSSM_FREE(privData.Data);
+ }
+ return ocrtn;
+}
+
+/*
+ * Generate FEE key pair with optional primeType, curveType, and seed (password) data.
+ */
+CSSM_RETURN cspGenFEEKeyPair(CSSM_CSP_HANDLE cspHand,
+ const char *keyLabel,
+ unsigned keyLabelLen,
+ uint32 keySize, // in bits
+ uint32 primeType, // CSSM_FEE_PRIME_TYPE_MERSENNE, etc.
+ uint32 curveType, // CSSM_FEE_CURVE_TYPE_MONTGOMERY, etc.
+ CSSM_KEY_PTR pubKey, // mallocd by caller
+ CSSM_BOOL pubIsRef, // true - reference key, false - data
+ uint32 pubKeyUsage, // CSSM_KEYUSE_ENCRYPT, etc.
+ CSSM_KEYBLOB_FORMAT pubFormat, // Optional. Specify 0 or CSSM_KEYBLOB_RAW_FORMAT_NONE
+ // to get the default format.
+ CSSM_KEY_PTR privKey, // mallocd by caller
+ CSSM_BOOL privIsRef, // true - reference key, false - data
+ uint32 privKeyUsage, // CSSM_KEYUSE_DECRYPT, etc.
+ CSSM_KEYBLOB_FORMAT privFormat, // optional 0 ==> default
+ const CSSM_DATA *seedData) // Present: CSP will hash this for private data.
+ // NULL: CSP generates random seed.
+{
+ CSSM_RETURN crtn;
+ CSSM_CC_HANDLE ccHand;
+ CSSM_CRYPTO_DATA privCData;
+ CSSM_CRYPTO_DATA_PTR privCDataPtr = NULL;
+ CSSM_DATA keyLabelData;
+ uint32 pubAttr;
+ uint32 privAttr;
+ CSSM_RETURN ocrtn = CSSM_OK;
+
+ /* pre-context-create algorithm-specific stuff */
+ if(seedData) {
+ privCData.Param = *((CSSM_DATA_PTR)seedData);
+ privCData.Callback = NULL;
+ privCDataPtr = &privCData;
+ }
+ /* else CSP generates random seed/key */
+
+ if(keySize == CSP_KEY_SIZE_DEFAULT) {
+ keySize = CSP_FEE_KEY_SIZE_DEFAULT;
+ }
+
+ keyLabelData.Data = (uint8 *)keyLabel,
+ keyLabelData.Length = keyLabelLen;
+ memset(pubKey, 0, sizeof(CSSM_KEY));
+ memset(privKey, 0, sizeof(CSSM_KEY));
+ setBadKeyData(pubKey);
+ setBadKeyData(privKey);
+
+ crtn = CSSM_CSP_CreateKeyGenContext(cspHand,
+ CSSM_ALGID_FEE,
+ keySize,
+ privCDataPtr, // Seed
+ NULL, // Salt
+ NULL, // StartDate
+ NULL, // EndDate
+ NULL, // Params
+ &ccHand);
+ if(crtn) {
+ printError("CSSM_CSP_CreateKeyGenContext", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+ /* cook up attribute bits */
+ if(pubIsRef) {
+ pubAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE;
+ }
+ else {
+ pubAttr = CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE;
+ }
+ if(privIsRef) {
+ privAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE;
+ }
+ else {
+ privAttr = CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE;
+ }
+
+ /* optional post-context-create stuff */
+ if(primeType != CSSM_FEE_PRIME_TYPE_DEFAULT) {
+ crtn = AddContextAttribute(ccHand,
+ CSSM_ATTRIBUTE_FEE_PRIME_TYPE,
+ sizeof(uint32),
+ CAT_Uint32,
+ NULL,
+ primeType);
+ if(crtn) {
+ printError("AddContextAttribute(CSSM_ATTRIBUTE_FEE_PRIME_TYPE)", crtn);
+ return crtn;
+ }
+ }
+ if(curveType != CSSM_FEE_CURVE_TYPE_DEFAULT) {
+ crtn = AddContextAttribute(ccHand,
+ CSSM_ATTRIBUTE_FEE_CURVE_TYPE,
+ sizeof(uint32),
+ CAT_Uint32,
+ NULL,
+ curveType);
+ if(crtn) {
+ printError("AddContextAttribute(CSSM_ATTRIBUTE_FEE_CURVE_TYPE)", crtn);
+ return crtn;
+ }
+ }
+
+ if(pubFormat != CSSM_KEYBLOB_RAW_FORMAT_NONE) {
+ crtn = AddContextAttribute(ccHand,
+ CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT,
+ sizeof(uint32),
+ CAT_Uint32,
+ NULL,
+ pubFormat);
+ if(crtn) {
+ printError("AddContextAttribute(CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT)", crtn);
+ return crtn;
+ }
+ }
+ if(privFormat != CSSM_KEYBLOB_RAW_FORMAT_NONE) {
+ crtn = AddContextAttribute(ccHand,
+ CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT,
+ sizeof(uint32), // currently sizeof CSSM_DATA
+ CAT_Uint32,
+ NULL,
+ pubFormat);
+ if(crtn) {
+ printError("AddContextAttribute(CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT)", crtn);
+ return crtn;
+ }
+ }
+ crtn = CSSM_GenerateKeyPair(ccHand,
+ pubKeyUsage,
+ pubAttr,
+ &keyLabelData,
+ pubKey,
+ privKeyUsage,
+ privAttr,
+ &keyLabelData, // same labels
+ NULL, // CredAndAclEntry
+ privKey);
+ if(crtn) {
+ printError("CSSM_GenerateKeyPair", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+ /* basic checks...*/
+ if(privIsRef) {
+ if(privKey->KeyHeader.BlobType != CSSM_KEYBLOB_REFERENCE) {
+ printf("privKey blob type: exp %u got %u\n",
+ CSSM_KEYBLOB_REFERENCE, (unsigned)privKey->KeyHeader.BlobType);
+ ocrtn = CSSM_ERRCODE_INTERNAL_ERROR;
+ goto abort;
+ }
+ }
+ else {
+ switch(privKey->KeyHeader.BlobType) {
+ case CSSM_KEYBLOB_RAW:
+ break;
+ default:
+ printf("privKey blob type: exp raw, got %u\n",
+ (unsigned)privKey->KeyHeader.BlobType);
+ ocrtn = CSSM_ERRCODE_INTERNAL_ERROR;
+ goto abort;
+ }
+ }
+ if(pubIsRef) {
+ if(pubKey->KeyHeader.BlobType != CSSM_KEYBLOB_REFERENCE) {
+ printf("pubKey blob type: exp %u got %u\n",
+ CSSM_KEYBLOB_REFERENCE, (unsigned)pubKey->KeyHeader.BlobType);
+ ocrtn = CSSM_ERRCODE_INTERNAL_ERROR;
+ goto abort;
+ }
+ }
+ else {
+ switch(pubKey->KeyHeader.BlobType) {
+ case CSSM_KEYBLOB_RAW:
+ break;
+ default:
+ printf("pubKey blob type: exp raw or raw_berder, got %u\n",
+ (unsigned)pubKey->KeyHeader.BlobType);
+ ocrtn = CSSM_ERRCODE_INTERNAL_ERROR;
+ goto abort;
+ }
+ }
+abort:
+ if(ccHand != 0) {
+ crtn = CSSM_DeleteContext(ccHand);
+ if(crtn) {
+ printError("CSSM_DeleteContext", crtn);
+ ocrtn = CSSM_ERRCODE_INTERNAL_ERROR;
+ }
+ }
+ return ocrtn;
+}
+
+/*
+ * Generate DSA key pair with optional generateAlgParams and optional
+ * incoming parameters.
+ */
+CSSM_RETURN cspGenDSAKeyPair(CSSM_CSP_HANDLE cspHand,
+ const char *keyLabel,
+ unsigned keyLabelLen,
+ uint32 keySize, // in bits
+ CSSM_KEY_PTR pubKey, // mallocd by caller
+ CSSM_BOOL pubIsRef, // true - reference key, false - data
+ uint32 pubKeyUsage, // CSSM_KEYUSE_ENCRYPT, etc.
+ CSSM_KEYBLOB_FORMAT pubFormat, // Optional. Specify 0 or CSSM_KEYBLOB_RAW_FORMAT_NONE
+ // to get the default format.
+ CSSM_KEY_PTR privKey, // mallocd by caller
+ CSSM_BOOL privIsRef, // true - reference key, false - data
+ uint32 privKeyUsage, // CSSM_KEYUSE_DECRYPT, etc.
+ CSSM_KEYBLOB_FORMAT privFormat, // Optional. Specify 0 or CSSM_KEYBLOB_RAW_FORMAT_NONE
+ // to get the default format.
+ CSSM_BOOL genParams,
+ CSSM_DATA_PTR paramData) // optional
+{
+ CSSM_RETURN crtn;
+ CSSM_CC_HANDLE ccHand;
+ CSSM_DATA keyLabelData;
+ uint32 pubAttr;
+ uint32 privAttr;
+ CSSM_RETURN ocrtn = CSSM_OK;
+
+ if(keySize == CSP_KEY_SIZE_DEFAULT) {
+ keySize = CSP_DSA_KEY_SIZE_DEFAULT;
+ }
+ keyLabelData.Data = (uint8 *)keyLabel,
+ keyLabelData.Length = keyLabelLen;
+ memset(pubKey, 0, sizeof(CSSM_KEY));
+ memset(privKey, 0, sizeof(CSSM_KEY));
+ setBadKeyData(pubKey);
+ setBadKeyData(privKey);
+
+ crtn = CSSM_CSP_CreateKeyGenContext(cspHand,
+ CSSM_ALGID_DSA,
+ keySize,
+ NULL, // Seed
+ NULL, // Salt
+ NULL, // StartDate
+ NULL, // EndDate
+ paramData,
+ &ccHand);
+ if(crtn) {
+ printError("CSSM_CSP_CreateKeyGenContext", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+
+ /* cook up attribute bits */
+ if(pubIsRef) {
+ pubAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE;
+ }
+ else {
+ pubAttr = CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE;
+ }
+ if(privIsRef) {
+ privAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE;
+ }
+ else {
+ privAttr = CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE;
+ }
+
+ if(genParams) {
+ /*
+ * extra step - generate params - this just adds some
+ * info to the context
+ */
+ CSSM_DATA dummy = {0, NULL};
+ crtn = CSSM_GenerateAlgorithmParams(ccHand,
+ keySize, &dummy);
+ if(crtn) {
+ printError("CSSM_GenerateAlgorithmParams", crtn);
+ return crtn;
+ }
+ appFreeCssmData(&dummy, CSSM_FALSE);
+ }
+
+ /* optional format specifiers */
+ if(!pubIsRef && (pubFormat != CSSM_KEYBLOB_RAW_FORMAT_NONE)) {
+ crtn = AddContextAttribute(ccHand,
+ CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT,
+ sizeof(uint32),
+ CAT_Uint32,
+ NULL,
+ pubFormat);
+ if(crtn) {
+ printError("AddContextAttribute(CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT)", crtn);
+ return crtn;
+ }
+ }
+ if(!privIsRef && (privFormat != CSSM_KEYBLOB_RAW_FORMAT_NONE)) {
+ crtn = AddContextAttribute(ccHand,
+ CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT,
+ sizeof(uint32), // currently sizeof CSSM_DATA
+ CAT_Uint32,
+ NULL,
+ privFormat);
+ if(crtn) {
+ printError("AddContextAttribute(CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT)", crtn);
+ return crtn;
+ }
+ }
+
+ crtn = CSSM_GenerateKeyPair(ccHand,
+ pubKeyUsage,
+ pubAttr,
+ &keyLabelData,
+ pubKey,
+ privKeyUsage,
+ privAttr,
+ &keyLabelData, // same labels
+ NULL, // CredAndAclEntry
+ privKey);
+ if(crtn) {
+ printError("CSSM_GenerateKeyPair", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+ /* basic checks...*/
+ if(privIsRef) {
+ if(privKey->KeyHeader.BlobType != CSSM_KEYBLOB_REFERENCE) {
+ printf("privKey blob type: exp %u got %u\n",
+ CSSM_KEYBLOB_REFERENCE, (unsigned)privKey->KeyHeader.BlobType);
+ ocrtn = CSSM_ERRCODE_INTERNAL_ERROR;
+ goto abort;
+ }
+ }
+ else {
+ switch(privKey->KeyHeader.BlobType) {
+ case CSSM_KEYBLOB_RAW:
+ break;
+ default:
+ printf("privKey blob type: exp raw, got %u\n",
+ (unsigned)privKey->KeyHeader.BlobType);
+ ocrtn = CSSM_ERRCODE_INTERNAL_ERROR;
+ goto abort;
+ }
+ }
+ if(pubIsRef) {
+ if(pubKey->KeyHeader.BlobType != CSSM_KEYBLOB_REFERENCE) {
+ printf("pubKey blob type: exp %u got %u\n",
+ CSSM_KEYBLOB_REFERENCE, (unsigned)pubKey->KeyHeader.BlobType);
+ ocrtn = CSSM_ERRCODE_INTERNAL_ERROR;
+ goto abort;
+ }
+ }
+ else {
+ switch(pubKey->KeyHeader.BlobType) {
+ case CSSM_KEYBLOB_RAW:
+ break;
+ default:
+ printf("pubKey blob type: exp raw or raw_berder, got %u\n",
+ (unsigned)pubKey->KeyHeader.BlobType);
+ ocrtn = CSSM_ERRCODE_INTERNAL_ERROR;
+ goto abort;
+ }
+ }
+abort:
+ if(ccHand != 0) {
+ crtn = CSSM_DeleteContext(ccHand);
+ if(crtn) {
+ printError("CSSM_DeleteContext", crtn);
+ ocrtn = CSSM_ERRCODE_INTERNAL_ERROR;
+ }
+ }
+ return ocrtn;
+}
+
+
+uint32 cspDefaultKeySize(uint32 alg)
+{
+ uint32 keySizeInBits;
+ switch(alg) {
+ case CSSM_ALGID_DES:
+ keySizeInBits = CSP_DES_KEY_SIZE_DEFAULT;
+ break;
+ case CSSM_ALGID_3DES_3KEY:
+ case CSSM_ALGID_DESX:
+ keySizeInBits = CSP_DES3_KEY_SIZE_DEFAULT;
+ break;
+ case CSSM_ALGID_RC2:
+ keySizeInBits = CSP_RC2_KEY_SIZE_DEFAULT;
+ break;
+ case CSSM_ALGID_RC4:
+ keySizeInBits = CSP_RC4_KEY_SIZE_DEFAULT;
+ break;
+ case CSSM_ALGID_RC5:
+ keySizeInBits = CSP_RC5_KEY_SIZE_DEFAULT;
+ break;
+ case CSSM_ALGID_ASC:
+ keySizeInBits = CSP_ASC_KEY_SIZE_DEFAULT;
+ break;
+ case CSSM_ALGID_BLOWFISH:
+ keySizeInBits = CSP_BFISH_KEY_SIZE_DEFAULT;
+ break;
+ case CSSM_ALGID_CAST:
+ keySizeInBits = CSP_CAST_KEY_SIZE_DEFAULT;
+ break;
+ case CSSM_ALGID_IDEA:
+ keySizeInBits = CSP_IDEA_KEY_SIZE_DEFAULT;
+ break;
+ case CSSM_ALGID_AES:
+ keySizeInBits = CSP_AES_KEY_SIZE_DEFAULT;
+ break;
+ case CSSM_ALGID_SHA1HMAC:
+ keySizeInBits = CSP_HMAC_SHA_KEY_SIZE_DEFAULT;
+ break;
+ case CSSM_ALGID_MD5HMAC:
+ keySizeInBits = CSP_HMAC_MD5_KEY_SIZE_DEFAULT;
+ break;
+ case CSSM_ALGID_FEE:
+ keySizeInBits = CSP_FEE_KEY_SIZE_DEFAULT;
+ break;
+ case CSSM_ALGID_RSA:
+ keySizeInBits = CSP_RSA_KEY_SIZE_DEFAULT;
+ break;
+ case CSSM_ALGID_DSA:
+ keySizeInBits = CSP_DSA_KEY_SIZE_DEFAULT;
+ break;
+ case CSSM_ALGID_ECDSA:
+ keySizeInBits = CSP_ECDSA_KEY_SIZE_DEFAULT;
+ break;
+ case CSSM_ALGID_NONE:
+ keySizeInBits = CSP_NULL_CRYPT_KEY_SIZE_DEF;
+ break;
+ default:
+ printf("***cspDefaultKeySize: Unknown symmetric algorithm\n");
+ keySizeInBits = 0;
+ break;
+ }
+ return keySizeInBits;
+}
+
+/*
+ * Create a random symmetric key.
+ */
+CSSM_KEY_PTR cspGenSymKey(CSSM_CSP_HANDLE cspHand,
+ uint32 alg,
+ const char *keyLabel,
+ unsigned keyLabelLen,
+ uint32 keyUsage, // CSSM_KEYUSE_ENCRYPT, etc.
+ uint32 keySizeInBits,
+ CSSM_BOOL refKey)
+{
+ CSSM_KEY_PTR symKey = (CSSM_KEY_PTR)CSSM_MALLOC(sizeof(CSSM_KEY));
+ CSSM_RETURN crtn;
+ CSSM_CC_HANDLE ccHand;
+ uint32 keyAttr;
+ CSSM_DATA dummyLabel;
+
+ if(symKey == NULL) {
+ printf("Insufficient heap space\n");
+ return NULL;
+ }
+ memset(symKey, 0, sizeof(CSSM_KEY));
+ setBadKeyData(symKey);
+ if(keySizeInBits == CSP_KEY_SIZE_DEFAULT) {
+ keySizeInBits = cspDefaultKeySize(alg);
+ }
+ 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);
+ goto errorOut;
+ }
+ if(refKey) {
+ keyAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE;
+ }
+ else {
+ keyAttr = CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE;
+ }
+ dummyLabel.Length = keyLabelLen;
+ dummyLabel.Data = (uint8 *)keyLabel;
+
+ crtn = CSSM_GenerateKey(ccHand,
+ keyUsage,
+ keyAttr,
+ &dummyLabel,
+ NULL, // ACL
+ symKey);
+ if(crtn) {
+ printError("CSSM_GenerateKey", crtn);
+ goto errorOut;
+ }
+ crtn = CSSM_DeleteContext(ccHand);
+ if(crtn) {
+ printError("CSSM_DeleteContext", crtn);
+ goto errorOut;
+ }
+ return symKey;
+errorOut:
+ CSSM_FREE(symKey);
+ return NULL;
+}
+
+/*
+ * Derive symmetric key.
+ * Note in the X CSP, we never return an IV.
+ */
+CSSM_KEY_PTR cspDeriveKey(CSSM_CSP_HANDLE cspHand,
+ uint32 deriveAlg, // CSSM_ALGID_PKCS5_PBKDF2, etc.
+ uint32 keyAlg, // CSSM_ALGID_RC5, etc.
+ const char *keyLabel,
+ unsigned keyLabelLen,
+ uint32 keyUsage, // CSSM_KEYUSE_ENCRYPT, etc.
+ uint32 keySizeInBits,
+ CSSM_BOOL isRefKey,
+ CSSM_DATA_PTR password, // in PKCS-5 lingo
+ CSSM_DATA_PTR salt, // ditto
+ uint32 iterationCnt, // ditto
+ CSSM_DATA_PTR initVector) // mallocd & RETURNED
+{
+ CSSM_KEY_PTR symKey = (CSSM_KEY_PTR)
+ CSSM_MALLOC(sizeof(CSSM_KEY));
+ CSSM_RETURN crtn;
+ CSSM_CC_HANDLE ccHand;
+ uint32 keyAttr;
+ CSSM_DATA dummyLabel;
+ CSSM_PKCS5_PBKDF2_PARAMS pbeParams;
+ CSSM_DATA pbeData;
+ CSSM_ACCESS_CREDENTIALS creds;
+
+ if(symKey == NULL) {
+ printf("Insufficient heap space\n");
+ return NULL;
+ }
+ memset(symKey, 0, sizeof(CSSM_KEY));
+ setBadKeyData(symKey);
+ memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
+ if(keySizeInBits == CSP_KEY_SIZE_DEFAULT) {
+ keySizeInBits = cspDefaultKeySize(keyAlg);
+ }
+ crtn = CSSM_CSP_CreateDeriveKeyContext(cspHand,
+ deriveAlg,
+ keyAlg,
+ keySizeInBits,
+ &creds,
+ NULL, // BaseKey
+ iterationCnt,
+ salt,
+ NULL, // seed
+ &ccHand);
+ if(crtn) {
+ printError("CSSM_CSP_CreateDeriveKeyContext", crtn);
+ goto errorOut;
+ }
+ keyAttr = CSSM_KEYATTR_EXTRACTABLE;
+ if(isRefKey) {
+ keyAttr |= (CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_SENSITIVE);
+ }
+ else {
+ keyAttr |= CSSM_KEYATTR_RETURN_DATA;
+ }
+ dummyLabel.Length = keyLabelLen;
+ dummyLabel.Data = (uint8 *)keyLabel;
+
+ /* passing in password is pretty strange....*/
+ pbeParams.Passphrase = *password;
+ pbeParams.PseudoRandomFunction =
+ CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1;
+ pbeData.Data = (uint8 *)&pbeParams;
+ pbeData.Length = sizeof(pbeParams);
+ crtn = CSSM_DeriveKey(ccHand,
+ &pbeData,
+ keyUsage,
+ keyAttr,
+ &dummyLabel,
+ NULL, // cred and acl
+ symKey);
+ if(crtn) {
+ printError("CSSM_DeriveKey", crtn);
+ goto errorOut;
+ }
+ /* copy IV back to caller */
+ /* Nope, not supported */
+ #if 0
+ if(pbeParams.InitVector.Data != NULL) {
+ if(initVector->Data != NULL) {
+ if(initVector->Length < pbeParams.InitVector.Length) {
+ printf("***Insufficient InitVector\n");
+ goto errorOut;
+ }
+ }
+ else {
+ initVector->Data =
+ (uint8 *)CSSM_MALLOC(pbeParams.InitVector.Length);
+ }
+ memmove(initVector->Data, pbeParams.InitVector.Data,
+ pbeParams.InitVector.Length);
+ initVector->Length = pbeParams.InitVector.Length;
+ CSSM_FREE(pbeParams.InitVector.Data);
+ }
+ else {
+ printf("***Warning: CSSM_DeriveKey, no InitVector\n");
+ }
+ #endif
+ crtn = CSSM_DeleteContext(ccHand);
+ if(crtn) {
+ printError("CSSM_DeleteContext", crtn);
+ goto errorOut;
+ }
+ return symKey;
+errorOut:
+ CSSM_FREE(symKey);
+ return NULL;
+}
+
+/*
+ * Cook up a symmetric key with specified key bits and other
+ * params. Currently the CSPDL can only deal with reference keys except when
+ * doing wrap/unwrap, so we manually cook up a raw key, then we null-unwrap it.
+ */
+CSSM_RETURN cspGenSymKeyWithBits(
+ CSSM_CSP_HANDLE cspHand,
+ CSSM_ALGORITHMS keyAlg,
+ CSSM_KEYUSE keyUsage,
+ const CSSM_DATA *keyBits,
+ unsigned keySizeInBytes,
+ CSSM_KEY_PTR refKey) // init'd and RETURNED
+{
+ CSSM_KEY rawKey;
+ CSSM_KEYHEADER_PTR hdr = &rawKey.KeyHeader;
+ CSSM_RETURN crtn;
+
+ /* set up a raw key the CSP will accept */
+ memset(&rawKey, 0, sizeof(CSSM_KEY));
+ hdr->HeaderVersion = CSSM_KEYHEADER_VERSION;
+ hdr->BlobType = CSSM_KEYBLOB_RAW;
+ hdr->Format = CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING;
+ hdr->AlgorithmId = keyAlg;
+ hdr->KeyClass = CSSM_KEYCLASS_SESSION_KEY;
+ hdr->LogicalKeySizeInBits = keySizeInBytes * 8;
+ hdr->KeyAttr = CSSM_KEYATTR_EXTRACTABLE;
+ hdr->KeyUsage = keyUsage;
+ appSetupCssmData(&rawKey.KeyData, keySizeInBytes);
+ memmove(rawKey.KeyData.Data, keyBits->Data, keySizeInBytes);
+
+ /* convert to a ref key */
+ crtn = cspRawKeyToRef(cspHand, &rawKey, refKey);
+ appFreeCssmData(&rawKey.KeyData, CSSM_FALSE);
+ return crtn;
+}
+
+/*
+ * Free a key. This frees a CSP's resources associated with the key if
+ * the key is a reference key. It also frees key->KeyData. The CSSM_KEY
+ * struct itself is not freed.
+ * Note this has no effect on the CSP or DL cached keys unless the incoming
+ * key is a reference key.
+ */
+CSSM_RETURN cspFreeKey(CSSM_CSP_HANDLE cspHand,
+ CSSM_KEY_PTR key)
+{
+ CSSM_RETURN crtn;
+ crtn = CSSM_FreeKey(cspHand,
+ NULL, // access cred
+ key,
+ CSSM_FALSE); // delete - OK? maybe should parameterize?
+ if(crtn) {
+ printError("CSSM_FreeKey", crtn);
+ }
+ return crtn;
+}
+
+/* generate a random and reasonable key size in bits for specified CSSM algorithm */
+uint32 randKeySizeBits(uint32 alg,
+ opType op) // OT_Encrypt, etc.
+{
+ uint32 minSize;
+ uint32 maxSize;
+ uint32 size;
+
+ switch(alg) {
+ case CSSM_ALGID_DES:
+ return CSP_DES_KEY_SIZE_DEFAULT;
+ case CSSM_ALGID_3DES_3KEY:
+ case CSSM_ALGID_DESX:
+ return CSP_DES3_KEY_SIZE_DEFAULT;
+ case CSSM_ALGID_ASC:
+ case CSSM_ALGID_RC2:
+ case CSSM_ALGID_RC4:
+ case CSSM_ALGID_RC5:
+ minSize = 5 * 8;
+ maxSize = MAX_KEY_SIZE_RC245_BYTES * 8 ; // somewhat arbitrary
+ break;
+ case CSSM_ALGID_BLOWFISH:
+ minSize = 32;
+ maxSize = 448;
+ break;
+ case CSSM_ALGID_CAST:
+ minSize = 40;
+ maxSize = 128;
+ break;
+ case CSSM_ALGID_IDEA:
+ return CSP_IDEA_KEY_SIZE_DEFAULT;
+ case CSSM_ALGID_RSA:
+ minSize = CSP_RSA_KEY_SIZE_DEFAULT;
+ maxSize = 1024;
+ break;
+ case CSSM_ALGID_DSA:
+ /* signature only, no export restriction */
+ minSize = 512;
+ maxSize = 1024;
+ break;
+ case CSSM_ALGID_SHA1HMAC:
+ minSize = 20 * 8;
+ maxSize = 256 * 8;
+ break;
+ case CSSM_ALGID_MD5HMAC:
+ minSize = 16 * 8;
+ maxSize = 256 * 8;
+ break;
+ case CSSM_ALGID_FEE:
+ /* FEE requires discrete sizes */
+ size = genRand(1,4);
+ switch(size) {
+ case 1:
+ return 31;
+ case 2:
+ if(alg == CSSM_ALGID_FEE) {
+ return 127;
+ }
+ else {
+ return 128;
+ }
+ case 3:
+ return 161;
+ case 4:
+ return 192;
+ default:
+ printf("randKeySizeBits: internal error\n");
+ return 0;
+ }
+ case CSSM_ALGID_ECDSA:
+ case CSSM_ALGID_SHA1WithECDSA:
+ /* ECDSA require discrete sizes */
+ size = genRand(1,4);
+ switch(size) {
+ case 1:
+ return 192;
+ case 2:
+ return 256;
+ case 3:
+ return 384;
+ case 4:
+ default:
+ return 521;
+ }
+ case CSSM_ALGID_AES:
+ size = genRand(1, 3);
+ switch(size) {
+ case 1:
+ return 128;
+ case 2:
+ return 192;
+ case 3:
+ return 256;
+ }
+ case CSSM_ALGID_NONE:
+ return CSP_NULL_CRYPT_KEY_SIZE_DEF;
+ default:
+ printf("randKeySizeBits: unknown alg\n");
+ return CSP_KEY_SIZE_DEFAULT;
+ }
+ size = genRand(minSize, maxSize);
+
+ /* per-alg postprocessing.... */
+ if(alg != CSSM_ALGID_RC2) {
+ size &= ~0x7;
+ }
+ switch(alg) {
+ case CSSM_ALGID_RSA:
+ // new for X - strong keys */
+ size &= ~(16 - 1);
+ break;
+ case CSSM_ALGID_DSA:
+ /* size mod 64 == 0 */
+ size &= ~(64 - 1);
+ break;
+ default:
+ break;
+ }
+ return size;
+}
+
+#pragma mark --------- Encrypt/Decrypt ---------
+
+/*
+ * Encrypt/Decrypt
+ */
+/*
+ * Common routine for encrypt/decrypt - cook up an appropriate context handle
+ */
+/*
+ * When true, effectiveKeySizeInBits is passed down via the Params argument.
+ * Otherwise, we add a customized context attribute.
+ * Setting this true works with the stock Intel CSSM; this may well change.
+ * Note this overloading prevent us from specifying RC5 rounds....
+ */
+#define EFFECTIVE_SIZE_VIA_PARAMS 0
+CSSM_CC_HANDLE genCryptHandle(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.
+ const CSSM_KEY *key0,
+ const CSSM_KEY *key1, // for CSSM_ALGID_FEED only - must be the
+ // public key
+ const CSSM_DATA *iv, // optional
+ uint32 effectiveKeySizeInBits, // 0 means skip this attribute
+ uint32 rounds) // ditto
+{
+ CSSM_CC_HANDLE cryptHand = 0;
+ uint32 params;
+ CSSM_RETURN crtn;
+ CSSM_ACCESS_CREDENTIALS creds;
+
+ memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
+ #if EFFECTIVE_SIZE_VIA_PARAMS
+ params = effectiveKeySizeInBits;
+ #else
+ params = 0;
+ #endif
+ switch(algorithm) {
+ case CSSM_ALGID_DES:
+ case CSSM_ALGID_3DES_3KEY_EDE:
+ case CSSM_ALGID_DESX:
+ case CSSM_ALGID_ASC:
+ case CSSM_ALGID_RC2:
+ case CSSM_ALGID_RC4:
+ case CSSM_ALGID_RC5:
+ case CSSM_ALGID_AES:
+ case CSSM_ALGID_BLOWFISH:
+ case CSSM_ALGID_CAST:
+ case CSSM_ALGID_IDEA:
+ case CSSM_ALGID_NONE: // used for wrapKey()
+ crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
+ algorithm,
+ mode,
+ NULL, // access cred
+ key0,
+ iv, // InitVector
+ padding,
+ NULL, // Params
+ &cryptHand);
+ if(crtn) {
+ printError("CSSM_CSP_CreateSymmetricContext", crtn);
+ return 0;
+ }
+ break;
+ case CSSM_ALGID_FEED:
+ case CSSM_ALGID_FEEDEXP:
+ case CSSM_ALGID_FEECFILE:
+ case CSSM_ALGID_RSA:
+ crtn = CSSM_CSP_CreateAsymmetricContext(cspHand,
+ algorithm,
+ &creds, // access
+ key0,
+ padding,
+ &cryptHand);
+ if(crtn) {
+ printError("CSSM_CSP_CreateAsymmetricContext", crtn);
+ return 0;
+ }
+ if(key1 != NULL) {
+ /*
+ * FEED, some CFILE. Add (non-standard) second key attribute.
+ */
+ crtn = AddContextAttribute(cryptHand,
+ CSSM_ATTRIBUTE_PUBLIC_KEY,
+ sizeof(CSSM_KEY), // currently sizeof CSSM_DATA
+ CAT_Ptr,
+ key1,
+ 0);
+ if(crtn) {
+ printError("AddContextAttribute", crtn);
+ return 0;
+ }
+ }
+ if(mode != CSSM_ALGMODE_NONE) {
+ /* special case, e.g., CSSM_ALGMODE_PUBLIC_KEY */
+ crtn = AddContextAttribute(cryptHand,
+ CSSM_ATTRIBUTE_MODE,
+ sizeof(uint32),
+ CAT_Uint32,
+ NULL,
+ mode);
+ if(crtn) {
+ printError("AddContextAttribute", crtn);
+ return 0;
+ }
+ }
+ break;
+ default:
+ printf("genCryptHandle: bogus algorithm\n");
+ return 0;
+ }
+ #if !EFFECTIVE_SIZE_VIA_PARAMS
+ /* add optional EffectiveKeySizeInBits and rounds attributes */
+ if(effectiveKeySizeInBits != 0) {
+ CSSM_CONTEXT_ATTRIBUTE attr;
+ attr.AttributeType = CSSM_ATTRIBUTE_EFFECTIVE_BITS;
+ attr.AttributeLength = sizeof(uint32);
+ attr.Attribute.Uint32 = effectiveKeySizeInBits;
+ crtn = CSSM_UpdateContextAttributes(
+ cryptHand,
+ 1,
+ &attr);
+ if(crtn) {
+ printError("CSSM_UpdateContextAttributes", crtn);
+ return crtn;
+ }
+ }
+ #endif
+
+ if(rounds != 0) {
+ CSSM_CONTEXT_ATTRIBUTE attr;
+ attr.AttributeType = CSSM_ATTRIBUTE_ROUNDS;
+ attr.AttributeLength = sizeof(uint32);
+ attr.Attribute.Uint32 = rounds;
+ crtn = CSSM_UpdateContextAttributes(
+ cryptHand,
+ 1,
+ &attr);
+ if(crtn) {
+ printError("CSSM_UpdateContextAttributes", crtn);
+ return crtn;
+ }
+ }
+
+ return cryptHand;
+}
+
+CSSM_RETURN cspEncrypt(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.
+ const CSSM_KEY *key, // public or session key
+ const CSSM_KEY *pubKey, // for CSSM_ALGID_FEED, CSSM_ALGID_FEECFILE only
+ uint32 effectiveKeySizeInBits, // 0 means skip this attribute
+ uint32 rounds, // ditto
+ const CSSM_DATA *iv, // init vector, optional
+ const CSSM_DATA *ptext,
+ CSSM_DATA_PTR ctext, // RETURNED
+ CSSM_BOOL mallocCtext) // if true, and ctext empty, malloc
+ // by getting size from CSP
+{
+ CSSM_CC_HANDLE cryptHand;
+ CSSM_RETURN crtn;
+ CSSM_SIZE bytesEncrypted;
+ CSSM_DATA remData = {0, NULL};
+ CSSM_RETURN ocrtn = CSSM_OK;
+ unsigned origCtextLen; // the amount we malloc, if any
+ CSSM_RETURN savedErr = CSSM_OK;
+ CSSM_BOOL restoreErr = CSSM_FALSE;
+
+ cryptHand = genCryptHandle(cspHand,
+ algorithm,
+ mode,
+ padding,
+ key,
+ pubKey,
+ iv,
+ effectiveKeySizeInBits,
+ rounds);
+ if(cryptHand == 0) {
+ return CSSMERR_CSSM_INTERNAL_ERROR;
+ }
+ if(mallocCtext && (ctext->Length == 0)) {
+ CSSM_QUERY_SIZE_DATA querySize;
+ querySize.SizeInputBlock = ptext->Length;
+ crtn = CSSM_QuerySize(cryptHand,
+ CSSM_TRUE, // encrypt
+ 1,
+ &querySize);
+ if(crtn) {
+ printError("CSSM_QuerySize", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+ if(querySize.SizeOutputBlock == 0) {
+ /* CSP couldn't figure this out; skip our malloc */
+ printf("***cspEncrypt: warning: cipherTextSize unknown; "
+ "skipping malloc\n");
+ origCtextLen = 0;
+ }
+ else {
+ ctext->Data = (uint8 *)
+ appMalloc(querySize.SizeOutputBlock, NULL);
+ if(ctext->Data == NULL) {
+ printf("Insufficient heap space\n");
+ ocrtn = CSSM_ERRCODE_MEMORY_ERROR;
+ goto abort;
+ }
+ ctext->Length = origCtextLen = querySize.SizeOutputBlock;
+ memset(ctext->Data, 0, ctext->Length);
+ }
+ }
+ else {
+ origCtextLen = ctext->Length;
+ }
+ crtn = CSSM_EncryptData(cryptHand,
+ ptext,
+ 1,
+ ctext,
+ 1,
+ &bytesEncrypted,
+ &remData);
+ if(crtn == CSSM_OK) {
+ /*
+ * Deal with remData - its contents are included in bytesEncrypted.
+ */
+ if((remData.Length != 0) && mallocCtext) {
+ /* shouldn't happen - right? */
+ if(bytesEncrypted > origCtextLen) {
+ /* malloc and copy a new one */
+ uint8 *newCdata = (uint8 *)appMalloc(bytesEncrypted, NULL);
+ printf("**Warning: app malloced cipherBuf, but got nonzero "
+ "remData!\n");
+ if(newCdata == NULL) {
+ printf("Insufficient heap space\n");
+ ocrtn = CSSM_ERRCODE_MEMORY_ERROR;
+ goto abort;
+ }
+ memmove(newCdata, ctext->Data, ctext->Length);
+ memmove(newCdata+ctext->Length, remData.Data, remData.Length);
+ CSSM_FREE(ctext->Data);
+ ctext->Data = newCdata;
+ }
+ else {
+ /* there's room left over */
+ memmove(ctext->Data+ctext->Length, remData.Data, remData.Length);
+ }
+ ctext->Length = bytesEncrypted;
+ }
+ // NOTE: We return the proper length in ctext....
+ ctext->Length = bytesEncrypted;
+ }
+ else {
+ savedErr = crtn;
+ restoreErr = CSSM_TRUE;
+ printError("CSSM_EncryptData", crtn);
+ }
+abort:
+ crtn = CSSM_DeleteContext(cryptHand);
+ if(crtn) {
+ printError("CSSM_DeleteContext", crtn);
+ ocrtn = crtn;
+ }
+ if(restoreErr) {
+ ocrtn = savedErr;
+ }
+ return ocrtn;
+}
+
+#define PAD_IMPLIES_RAND_PTEXTSIZE 1
+#define LOG_STAGED_OPS 0
+#if LOG_STAGED_OPS
+#define soprintf(s) printf s
+#else
+#define soprintf(s)
+#endif
+
+CSSM_RETURN cspStagedEncrypt(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.
+ const CSSM_KEY *key, // public or session key
+ const CSSM_KEY *pubKey, // for CSSM_ALGID_FEED, CSSM_ALGID_FEECFILE only
+ uint32 effectiveKeySizeInBits, // 0 means skip this attribute
+ uint32 cipherBlockSize, // ditto
+ uint32 rounds, // ditto
+ const CSSM_DATA *iv, // init vector, optional
+ const CSSM_DATA *ptext,
+ CSSM_DATA_PTR ctext, // RETURNED, we malloc
+ CSSM_BOOL multiUpdates) // false:single update, true:multi updates
+{
+ CSSM_CC_HANDLE cryptHand;
+ CSSM_RETURN crtn;
+ CSSM_SIZE bytesEncrypted; // per update
+ CSSM_SIZE bytesEncryptedTotal = 0;
+ CSSM_RETURN ocrtn = CSSM_OK; // 'our' crtn
+ unsigned toMove; // remaining
+ unsigned thisMove; // bytes to encrypt on this update
+ CSSM_DATA thisPtext; // running ptr into ptext
+ CSSM_DATA ctextWork; // per update, mallocd by CSP
+ CSSM_QUERY_SIZE_DATA querySize;
+ uint8 *origCtext; // initial ctext->Data
+ unsigned origCtextLen; // amount we mallocd
+ CSSM_BOOL restoreErr = CSSM_FALSE;
+ CSSM_RETURN savedErr = CSSM_OK;
+
+
+ cryptHand = genCryptHandle(cspHand,
+ algorithm,
+ mode,
+ padding,
+ key,
+ pubKey,
+ iv,
+ effectiveKeySizeInBits,
+ rounds);
+ if(cryptHand == 0) {
+ return CSSMERR_CSP_INTERNAL_ERROR;
+ }
+ if(cipherBlockSize) {
+ crtn = AddContextAttribute(cryptHand,
+ CSSM_ATTRIBUTE_BLOCK_SIZE,
+ sizeof(uint32),
+ CAT_Uint32,
+ NULL,
+ cipherBlockSize);
+ if(crtn) {
+ printError("CSSM_UpdateContextAttributes", crtn);
+ goto abort;
+ }
+ }
+
+ /* obtain total required ciphertext size and block size */
+ querySize.SizeInputBlock = ptext->Length;
+ crtn = CSSM_QuerySize(cryptHand,
+ CSSM_TRUE, // encrypt
+ 1,
+ &querySize);
+ if(crtn) {
+ printError("CSSM_QuerySize(1)", crtn);
+ ocrtn = CSSMERR_CSP_INTERNAL_ERROR;
+ goto abort;
+ }
+ if(querySize.SizeOutputBlock == 0) {
+ /* CSP couldn't figure this out; skip our malloc - caller is taking its
+ * chances */
+ printf("***cspStagedEncrypt: warning: cipherTextSize unknown; aborting\n");
+ ocrtn = CSSMERR_CSP_INTERNAL_ERROR;
+ goto abort;
+ }
+ else {
+ origCtextLen = querySize.SizeOutputBlock;
+ if(algorithm == CSSM_ALGID_ASC) {
+ /* ASC is weird - the more chunks we do, the bigger the
+ * resulting ctext...*/
+ origCtextLen *= 2;
+ }
+ ctext->Length = origCtextLen;
+ ctext->Data = origCtext = (uint8 *)appMalloc(origCtextLen, NULL);
+ if(ctext->Data == NULL) {
+ printf("Insufficient heap space\n");
+ ocrtn = CSSMERR_CSP_MEMORY_ERROR;
+ goto abort;
+ }
+ memset(ctext->Data, 0, ctext->Length);
+ }
+
+ crtn = CSSM_EncryptDataInit(cryptHand);
+ if(crtn) {
+ printError("CSSM_EncryptDataInit", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+
+ toMove = ptext->Length;
+ thisPtext.Data = ptext->Data;
+ while(toMove) {
+ if(multiUpdates) {
+ thisMove = genRand(1, toMove);
+ }
+ else {
+ /* just do one pass thru this loop */
+ thisMove = toMove;
+ }
+ thisPtext.Length = thisMove;
+ /* let CSP do the individual mallocs */
+ ctextWork.Data = NULL;
+ ctextWork.Length = 0;
+ soprintf(("*** EncryptDataUpdate: ptextLen 0x%x\n", thisMove));
+ crtn = CSSM_EncryptDataUpdate(cryptHand,
+ &thisPtext,
+ 1,
+ &ctextWork,
+ 1,
+ &bytesEncrypted);
+ if(crtn) {
+ printError("CSSM_EncryptDataUpdate", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+ // NOTE: We return the proper length in ctext....
+ ctextWork.Length = bytesEncrypted;
+ soprintf(("*** EncryptDataUpdate: ptextLen 0x%x bytesEncrypted 0x%x\n",
+ thisMove, bytesEncrypted));
+ thisPtext.Data += thisMove;
+ toMove -= thisMove;
+ if(bytesEncrypted > ctext->Length) {
+ printf("cspStagedEncrypt: ctext overflow!\n");
+ ocrtn = crtn;
+ goto abort;
+ }
+ if(bytesEncrypted != 0) {
+ memmove(ctext->Data, ctextWork.Data, bytesEncrypted);
+ bytesEncryptedTotal += bytesEncrypted;
+ ctext->Data += bytesEncrypted;
+ ctext->Length -= bytesEncrypted;
+ }
+ if(ctextWork.Data != NULL) {
+ CSSM_FREE(ctextWork.Data);
+ }
+ }
+ /* OK, one more */
+ ctextWork.Data = NULL;
+ ctextWork.Length = 0;
+ crtn = CSSM_EncryptDataFinal(cryptHand, &ctextWork);
+ if(crtn) {
+ printError("CSSM_EncryptDataFinal", crtn);
+ savedErr = crtn;
+ restoreErr = CSSM_TRUE;
+ goto abort;
+ }
+ if(ctextWork.Length != 0) {
+ bytesEncryptedTotal += ctextWork.Length;
+ if(ctextWork.Length > ctext->Length) {
+ printf("cspStagedEncrypt: ctext overflow (2)!\n");
+ ocrtn = CSSMERR_CSP_INTERNAL_ERROR;
+ goto abort;
+ }
+ memmove(ctext->Data, ctextWork.Data, ctextWork.Length);
+ }
+ if(ctextWork.Data) {
+ /* this could have gotten mallocd and Length still be zero */
+ CSSM_FREE(ctextWork.Data);
+ }
+
+ /* retweeze ctext */
+ ctext->Data = origCtext;
+ ctext->Length = bytesEncryptedTotal;
+abort:
+ crtn = CSSM_DeleteContext(cryptHand);
+ if(crtn) {
+ printError("CSSM_DeleteContext", crtn);
+ ocrtn = crtn;
+ }
+ if(restoreErr) {
+ /* give caller the error from the encrypt */
+ ocrtn = savedErr;
+ }
+ return ocrtn;
+}
+
+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.
+ const CSSM_KEY *key, // public or session key
+ const CSSM_KEY *pubKey, // for CSSM_ALGID_FEED, CSSM_ALGID_FEECFILE only
+ uint32 effectiveKeySizeInBits, // 0 means skip this attribute
+ uint32 rounds, // ditto
+ const CSSM_DATA *iv, // init vector, optional
+ const CSSM_DATA *ctext,
+ CSSM_DATA_PTR ptext, // RETURNED
+ CSSM_BOOL mallocPtext) // if true and ptext->Length = 0,
+ // we'll malloc
+{
+ CSSM_CC_HANDLE cryptHand;
+ CSSM_RETURN crtn;
+ CSSM_RETURN ocrtn = CSSM_OK;
+ CSSM_SIZE bytesDecrypted;
+ CSSM_DATA remData = {0, NULL};
+ unsigned origPtextLen; // the amount we malloc, if any
+
+ cryptHand = genCryptHandle(cspHand,
+ algorithm,
+ mode,
+ padding,
+ key,
+ pubKey,
+ iv,
+ effectiveKeySizeInBits,
+ rounds);
+ if(cryptHand == 0) {
+ return CSSMERR_CSP_INTERNAL_ERROR;
+ }
+ if(mallocPtext && (ptext->Length == 0)) {
+ CSSM_QUERY_SIZE_DATA querySize;
+ querySize.SizeInputBlock = ctext->Length;
+ crtn = CSSM_QuerySize(cryptHand,
+ CSSM_FALSE, // encrypt
+ 1,
+ &querySize);
+ if(crtn) {
+ printError("CSSM_QuerySize", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+ if(querySize.SizeOutputBlock == 0) {
+ /* CSP couldn't figure this one out; skip our malloc */
+ printf("***cspDecrypt: warning: plainTextSize unknown; "
+ "skipping malloc\n");
+ origPtextLen = 0;
+ }
+ else {
+ ptext->Data =
+ (uint8 *)appMalloc(querySize.SizeOutputBlock, NULL);
+ if(ptext->Data == NULL) {
+ printf("Insufficient heap space\n");
+ ocrtn = CSSMERR_CSP_MEMORY_ERROR;
+ goto abort;
+ }
+ ptext->Length = origPtextLen = querySize.SizeOutputBlock;
+ memset(ptext->Data, 0, ptext->Length);
+ }
+ }
+ else {
+ origPtextLen = ptext->Length;
+ }
+ crtn = CSSM_DecryptData(cryptHand,
+ ctext,
+ 1,
+ ptext,
+ 1,
+ &bytesDecrypted,
+ &remData);
+ if(crtn == CSSM_OK) {
+ /*
+ * Deal with remData - its contents are included in bytesDecrypted.
+ */
+ if((remData.Length != 0) && mallocPtext) {
+ /* shouldn't happen - right? */
+ if(bytesDecrypted > origPtextLen) {
+ /* malloc and copy a new one */
+ uint8 *newPdata = (uint8 *)appMalloc(bytesDecrypted, NULL);
+ printf("**Warning: app malloced ClearBuf, but got nonzero "
+ "remData!\n");
+ if(newPdata == NULL) {
+ printf("Insufficient heap space\n");
+ ocrtn = CSSMERR_CSP_MEMORY_ERROR;
+ goto abort;
+ }
+ memmove(newPdata, ptext->Data, ptext->Length);
+ memmove(newPdata + ptext->Length,
+ remData.Data, remData.Length);
+ CSSM_FREE(ptext->Data);
+ ptext->Data = newPdata;
+ }
+ else {
+ /* there's room left over */
+ memmove(ptext->Data + ptext->Length,
+ remData.Data, remData.Length);
+ }
+ ptext->Length = bytesDecrypted;
+ }
+ // 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;
+ }
+abort:
+ crtn = CSSM_DeleteContext(cryptHand);
+ if(crtn) {
+ printError("CSSM_DeleteContext", crtn);
+ ocrtn = crtn;
+ }
+ return ocrtn;
+}
+
+CSSM_RETURN cspStagedDecrypt(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.
+ const CSSM_KEY *key, // public or session key
+ const CSSM_KEY *pubKey, // for CSSM_ALGID_FEED, CSSM_ALGID_FEECFILE only
+ uint32 effectiveKeySizeInBits, // 0 means skip this attribute
+ uint32 cipherBlockSize, // ditto
+ uint32 rounds, // ditto
+ const CSSM_DATA *iv, // init vector, optional
+ const CSSM_DATA *ctext,
+ CSSM_DATA_PTR ptext, // RETURNED, we malloc
+ CSSM_BOOL multiUpdates) // false:single update, true:multi updates
+{
+ CSSM_CC_HANDLE cryptHand;
+ CSSM_RETURN crtn;
+ CSSM_SIZE bytesDecrypted; // per update
+ CSSM_SIZE bytesDecryptedTotal = 0;
+ CSSM_RETURN ocrtn = CSSM_OK; // 'our' crtn
+ unsigned toMove; // remaining
+ unsigned thisMove; // bytes to encrypt on this update
+ CSSM_DATA thisCtext; // running ptr into ptext
+ CSSM_DATA ptextWork; // per update, mallocd by CSP
+ CSSM_QUERY_SIZE_DATA querySize;
+ uint8 *origPtext; // initial ptext->Data
+ unsigned origPtextLen; // amount we mallocd
+
+ cryptHand = genCryptHandle(cspHand,
+ algorithm,
+ mode,
+ padding,
+ key,
+ pubKey,
+ iv,
+ effectiveKeySizeInBits,
+ rounds);
+ if(cryptHand == 0) {
+ return CSSMERR_CSP_INTERNAL_ERROR;
+ }
+ if(cipherBlockSize) {
+ crtn = AddContextAttribute(cryptHand,
+ CSSM_ATTRIBUTE_BLOCK_SIZE,
+ sizeof(uint32),
+ CAT_Uint32,
+ NULL,
+ cipherBlockSize);
+ if(crtn) {
+ printError("CSSM_UpdateContextAttributes", crtn);
+ goto abort;
+ }
+ }
+
+ /* obtain total required ciphertext size and block size */
+ querySize.SizeInputBlock = ctext->Length;
+ crtn = CSSM_QuerySize(cryptHand,
+ CSSM_FALSE, // encrypt
+ 1,
+ &querySize);
+ if(crtn) {
+ printError("CSSM_QuerySize(1)", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+
+ /* required ptext size should be independent of number of chunks */
+ if(querySize.SizeOutputBlock == 0) {
+ printf("***warning: cspStagedDecrypt: plainTextSize unknown; aborting\n");
+ ocrtn = CSSMERR_CSP_INTERNAL_ERROR;
+ goto abort;
+ }
+ else {
+ // until exit, ptext->Length indicates remaining bytes of usable data in
+ // ptext->Data
+ ptext->Length = origPtextLen = querySize.SizeOutputBlock;
+ ptext->Data = origPtext =
+ (uint8 *)appMalloc(origPtextLen, NULL);
+ if(ptext->Data == NULL) {
+ printf("Insufficient heap space\n");
+ ocrtn = CSSMERR_CSP_INTERNAL_ERROR;
+ goto abort;
+ }
+ memset(ptext->Data, 0, ptext->Length);
+ }
+
+ crtn = CSSM_DecryptDataInit(cryptHand);
+ if(crtn) {
+ printError("CSSM_DecryptDataInit", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+ toMove = ctext->Length;
+ thisCtext.Data = ctext->Data;
+ while(toMove) {
+ if(multiUpdates) {
+ thisMove = genRand(1, toMove);
+ }
+ else {
+ /* just do one pass thru this loop */
+ thisMove = toMove;
+ }
+ thisCtext.Length = thisMove;
+ /* let CSP do the individual mallocs */
+ ptextWork.Data = NULL;
+ ptextWork.Length = 0;
+ soprintf(("*** DecryptDataUpdate: ctextLen 0x%x\n", thisMove));
+ crtn = CSSM_DecryptDataUpdate(cryptHand,
+ &thisCtext,
+ 1,
+ &ptextWork,
+ 1,
+ &bytesDecrypted);
+ if(crtn) {
+ printError("CSSM_DecryptDataUpdate", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+ //
+ // NOTE: We return the proper length in ptext....
+ ptextWork.Length = bytesDecrypted;
+ thisCtext.Data += thisMove;
+ toMove -= thisMove;
+ if(bytesDecrypted > ptext->Length) {
+ printf("cspStagedDecrypt: ptext overflow!\n");
+ ocrtn = CSSMERR_CSP_INTERNAL_ERROR;
+ goto abort;
+ }
+ if(bytesDecrypted != 0) {
+ memmove(ptext->Data, ptextWork.Data, bytesDecrypted);
+ bytesDecryptedTotal += bytesDecrypted;
+ ptext->Data += bytesDecrypted;
+ ptext->Length -= bytesDecrypted;
+ }
+ if(ptextWork.Data != NULL) {
+ CSSM_FREE(ptextWork.Data);
+ }
+ }
+ /* OK, one more */
+ ptextWork.Data = NULL;
+ ptextWork.Length = 0;
+ crtn = CSSM_DecryptDataFinal(cryptHand, &ptextWork);
+ if(crtn) {
+ printError("CSSM_DecryptDataFinal", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+ if(ptextWork.Length != 0) {
+ bytesDecryptedTotal += ptextWork.Length;
+ if(ptextWork.Length > ptext->Length) {
+ printf("cspStagedDecrypt: ptext overflow (2)!\n");
+ ocrtn = CSSMERR_CSP_INTERNAL_ERROR;
+ goto abort;
+ }
+ memmove(ptext->Data, ptextWork.Data, ptextWork.Length);
+ }
+ if(ptextWork.Data) {
+ /* this could have gotten mallocd and Length still be zero */
+ CSSM_FREE(ptextWork.Data);
+ }
+
+ /* retweeze ptext */
+ ptext->Data = origPtext;
+ ptext->Length = bytesDecryptedTotal;
+abort:
+ crtn = CSSM_DeleteContext(cryptHand);
+ if(crtn) {
+ printError("CSSM_DeleteContext", crtn);
+ ocrtn = crtn;
+ }
+ return ocrtn;
+}
+
+#pragma mark --------- sign/verify/MAC ---------
+
+/*
+ * Signature routines
+ * This all-in-one sign op has a special case for RSA keys. If the requested
+ * alg is MD5 or SHA1, we'll do a manual digest op followed by raw RSA sign.
+ * Likewise, if it's CSSM_ALGID_DSA, we'll do manual SHA1 digest followed by
+ * raw DSA sign.
+ */
+
+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_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;
+ }
+ 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;
+}
+
+/*
+ * Staged sign. Each update does a random number of bytes 'till through.
+ */
+CSSM_RETURN cspStagedSign(CSSM_CSP_HANDLE cspHand,
+ uint32 algorithm, // CSSM_ALGID_FEE_MD5, etc.
+ CSSM_KEY_PTR key, // private key
+ const CSSM_DATA *text,
+ CSSM_BOOL multiUpdates, // false:single update, true:multi updates
+ CSSM_DATA_PTR sig) // RETURNED
+{
+ CSSM_CC_HANDLE sigHand;
+ CSSM_RETURN crtn;
+ CSSM_RETURN ocrtn = CSSM_OK;
+ unsigned thisMove; // this update
+ unsigned toMove; // total to go
+ CSSM_DATA thisText; // actaully passed to update
+ crtn = CSSM_CSP_CreateSignatureContext(cspHand,
+ algorithm,
+ NULL, // passPhrase
+ key,
+ &sigHand);
+ if(crtn) {
+ printError("CSSM_CSP_CreateSignatureContext (1)", crtn);
+ return crtn;
+ }
+ crtn = CSSM_SignDataInit(sigHand);
+ if(crtn) {
+ printError("CSSM_SignDataInit", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+ toMove = text->Length;
+ thisText.Data = text->Data;
+ while(toMove) {
+ if(multiUpdates) {
+ thisMove = genRand(1, toMove);
+ }
+ else {
+ thisMove = toMove;
+ }
+ thisText.Length = thisMove;
+ crtn = CSSM_SignDataUpdate(sigHand,
+ &thisText,
+ 1);
+ if(crtn) {
+ printError("CSSM_SignDataUpdate", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+ thisText.Data += thisMove;
+ toMove -= thisMove;
+ }
+ crtn = CSSM_SignDataFinal(sigHand, sig);
+ if(crtn) {
+ printError("CSSM_SignDataFinal", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+abort:
+ crtn = CSSM_DeleteContext(sigHand);
+ if(crtn) {
+ printError("CSSM_DeleteContext", crtn);
+ ocrtn = crtn;
+ }
+ return ocrtn;
+}
+
+/*
+ * This all-in-one verify op has a special case for RSA keys. If the requested
+ * alg is MD5 or SHA1, we'll do a manual digest op followed by raw RSA verify.
+ * Likewise, if it's CSSM_ALGID_DSA, we'll do manual SHA1 digest followed by
+ * raw DSA sign.
+ */
+
+CSSM_RETURN cspSigVerify(CSSM_CSP_HANDLE cspHand,
+ uint32 algorithm, // CSSM_ALGID_FEE_MD5, etc.
+ CSSM_KEY_PTR key, // public key
+ const CSSM_DATA *text,
+ const CSSM_DATA *sig,
+ CSSM_RETURN expectResult) // expected result is verify failure
+ // CSSM_OK - expect success
+{
+ CSSM_CC_HANDLE sigHand;
+ CSSM_RETURN ocrtn = CSSM_OK;
+ CSSM_RETURN crtn;
+ 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 (3)", crtn);
+ return crtn;
+ }
+
+ crtn = CSSM_VerifyData(sigHand,
+ ptext,
+ 1,
+ digestAlg,
+ sig);
+ if(crtn != expectResult) {
+ if(!crtn) {
+ printf("Unexpected good Sig Verify\n");
+ }
+ else {
+ printError("CSSM_VerifyData", crtn);
+ }
+ ocrtn = CSSMERR_CSSM_INTERNAL_ERROR;
+ }
+ crtn = CSSM_DeleteContext(sigHand);
+ if(crtn) {
+ printError("CSSM_DeleteContext", crtn);
+ ocrtn = crtn;
+ }
+ if(digest.Data != NULL) {
+ CSSM_FREE(digest.Data);
+ }
+ return ocrtn;
+}
+
+/*
+ * Staged verify. Each update does a random number of bytes 'till through.
+ */
+CSSM_RETURN cspStagedSigVerify(CSSM_CSP_HANDLE cspHand,
+ uint32 algorithm, // CSSM_ALGID_FEE_MD5, etc.
+ CSSM_KEY_PTR key, // private key
+ const CSSM_DATA *text,
+ const CSSM_DATA *sig,
+ CSSM_BOOL multiUpdates, // false:single update, true:multi updates
+ CSSM_RETURN expectResult) // expected result is verify failure
+ // CSSM_TRUE - expect success
+{
+ CSSM_CC_HANDLE sigHand;
+ CSSM_RETURN crtn;
+ CSSM_RETURN ocrtn = CSSM_OK;
+ unsigned thisMove; // this update
+ unsigned toMove; // total to go
+ CSSM_DATA thisText; // actaully passed to update
+ crtn = CSSM_CSP_CreateSignatureContext(cspHand,
+ algorithm,
+ NULL, // passPhrase
+ key,
+ &sigHand);
+ if(crtn) {
+ printError("CSSM_CSP_CreateSignatureContext (4)", crtn);
+ return crtn;
+ }
+ crtn = CSSM_VerifyDataInit(sigHand);
+ if(crtn) {
+ printError("CSSM_VerifyDataInit", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+ toMove = text->Length;
+ thisText.Data = text->Data;
+ while(toMove) {
+ if(multiUpdates) {
+ thisMove = genRand(1, toMove);
+ }
+ else {
+ thisMove = toMove;
+ }
+ thisText.Length = thisMove;
+ crtn = CSSM_VerifyDataUpdate(sigHand,
+ &thisText,
+ 1);
+ if(crtn) {
+ printError("CSSM_VerifyDataUpdate", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+ thisText.Data += thisMove;
+ toMove -= thisMove;
+ }
+ crtn = CSSM_VerifyDataFinal(sigHand, sig);
+ if(crtn != expectResult) {
+ if(crtn) {
+ printError("CSSM_VerifyDataFinal", crtn);
+ }
+ else {
+ printf("Unexpected good Staged Sig Verify\n");
+ }
+ ocrtn = CSSMERR_CSSM_INTERNAL_ERROR;
+ }
+abort:
+ crtn = CSSM_DeleteContext(sigHand);
+ if(crtn) {
+ printError("CSSM_DeleteContext", crtn);
+ ocrtn = crtn;
+ }
+ return ocrtn;
+}
+
+/*
+ * MAC routines
+ */
+CSSM_RETURN cspGenMac(CSSM_CSP_HANDLE cspHand,
+ uint32 algorithm, // CSSM_ALGID_FEE_MD5, etc.
+ CSSM_KEY_PTR key, // session key
+ const CSSM_DATA *text,
+ CSSM_DATA_PTR mac) // RETURNED
+{
+ CSSM_CC_HANDLE macHand;
+ CSSM_RETURN crtn;
+ CSSM_RETURN ocrtn = CSSM_OK;
+ crtn = CSSM_CSP_CreateMacContext(cspHand,
+ algorithm,
+ key,
+ &macHand);
+ if(crtn) {
+ printError("CSSM_CSP_CreateMacContext (1)", crtn);
+ return crtn;
+ }
+ crtn = CSSM_GenerateMac(macHand,
+ text,
+ 1,
+ mac);
+ if(crtn) {
+ printError("CSSM_GenerateMac", crtn);
+ ocrtn = crtn;
+ }
+ crtn = CSSM_DeleteContext(macHand);
+ if(crtn) {
+ printError("CSSM_DeleteContext", crtn);
+ ocrtn = crtn;
+ }
+ return ocrtn;
+}
+
+/*
+ * Staged generate mac.
+ */
+CSSM_RETURN cspStagedGenMac(CSSM_CSP_HANDLE cspHand,
+ uint32 algorithm, // CSSM_ALGID_FEE_MD5, etc.
+ CSSM_KEY_PTR key, // private key
+ const CSSM_DATA *text,
+ CSSM_BOOL mallocMac, // if true and digest->Length = 0, we'll
+ // malloc
+ CSSM_BOOL multiUpdates, // false:single update, true:multi updates
+ CSSM_DATA_PTR mac) // RETURNED
+{
+ CSSM_CC_HANDLE macHand;
+ CSSM_RETURN crtn;
+ CSSM_RETURN ocrtn = CSSM_OK;
+ unsigned thisMove; // this update
+ unsigned toMove; // total to go
+ CSSM_DATA thisText; // actaully passed to update
+
+ crtn = CSSM_CSP_CreateMacContext(cspHand,
+ algorithm,
+ key,
+ &macHand);
+ if(crtn) {
+ printError("CSSM_CSP_CreateMacContext (2)", crtn);
+ return crtn;
+ }
+
+ if(mallocMac && (mac->Length == 0)) {
+ /* malloc mac - ask CSP for size */
+ CSSM_QUERY_SIZE_DATA querySize = {0, 0};
+ crtn = CSSM_QuerySize(macHand,
+ CSSM_TRUE, // encrypt
+ 1,
+ &querySize);
+ if(crtn) {
+ printError("CSSM_QuerySize(mac)", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+ if(querySize.SizeOutputBlock == 0) {
+ printf("Unknown mac size\n");
+ ocrtn = CSSMERR_CSSM_INTERNAL_ERROR;
+ goto abort;
+ }
+ mac->Data = (uint8 *)appMalloc(querySize.SizeOutputBlock, NULL);
+ if(mac->Data == NULL) {
+ printf("malloc failure\n");
+ ocrtn = CSSMERR_CSSM_MEMORY_ERROR;
+ goto abort;
+ }
+ mac->Length = querySize.SizeOutputBlock;
+ }
+
+ crtn = CSSM_GenerateMacInit(macHand);
+ if(crtn) {
+ printError("CSSM_GenerateMacInit", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+ toMove = text->Length;
+ thisText.Data = text->Data;
+
+ while(toMove) {
+ if(multiUpdates) {
+ thisMove = genRand(1, toMove);
+ }
+ else {
+ thisMove = toMove;
+ }
+ thisText.Length = thisMove;
+ crtn = CSSM_GenerateMacUpdate(macHand,
+ &thisText,
+ 1);
+ if(crtn) {
+ printError("CSSM_GenerateMacUpdate", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+ thisText.Data += thisMove;
+ toMove -= thisMove;
+ }
+ crtn = CSSM_GenerateMacFinal(macHand, mac);
+ if(crtn) {
+ printError("CSSM_GenerateMacFinal", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+abort:
+ crtn = CSSM_DeleteContext(macHand);
+ if(crtn) {
+ printError("CSSM_DeleteContext", crtn);
+ ocrtn = crtn;
+ }
+ return ocrtn;
+}
+
+CSSM_RETURN cspMacVerify(CSSM_CSP_HANDLE cspHand,
+ uint32 algorithm, // CSSM_ALGID_FEE_MD5, etc.
+ CSSM_KEY_PTR key, // public key
+ const CSSM_DATA *text,
+ const CSSM_DATA_PTR mac,
+ CSSM_RETURN expectResult) // expected result
+ // CSSM_OK - expect success
+{
+ CSSM_CC_HANDLE macHand;
+ CSSM_RETURN ocrtn = CSSM_OK;
+ CSSM_RETURN crtn;
+ crtn = CSSM_CSP_CreateMacContext(cspHand,
+ algorithm,
+ key,
+ &macHand);
+ if(crtn) {
+ printError("CSSM_CSP_CreateMacContext (3)", crtn);
+ return crtn;
+ }
+ crtn = CSSM_VerifyMac(macHand,
+ text,
+ 1,
+ mac);
+ if(crtn != expectResult) {
+ if(crtn) {
+ printError("CSSM_VerifyMac", crtn);
+ }
+ else {
+ printf("Unexpected good Mac Verify\n");
+ }
+ ocrtn = CSSMERR_CSSM_INTERNAL_ERROR;
+ }
+ crtn = CSSM_DeleteContext(macHand);
+ if(crtn) {
+ printError("CSSM_DeleteContext", crtn);
+ ocrtn = crtn;
+ }
+ return ocrtn;
+}
+
+/*
+ * Staged mac verify. Each update does a random number of bytes 'till through.
+ */
+CSSM_RETURN cspStagedMacVerify(CSSM_CSP_HANDLE cspHand,
+ uint32 algorithm, // CSSM_ALGID_FEE_MD5, etc.
+ CSSM_KEY_PTR key, // private key
+ const CSSM_DATA *text,
+ const CSSM_DATA_PTR mac,
+ CSSM_BOOL multiUpdates, // false:single update, true:multi updates
+ CSSM_RETURN expectResult) // expected result is verify failure
+ // CSSM_OK - expect success
+{
+ CSSM_CC_HANDLE macHand;
+ CSSM_RETURN crtn;
+ CSSM_RETURN ocrtn = CSSM_OK;
+ unsigned thisMove; // this update
+ unsigned toMove; // total to go
+ CSSM_DATA thisText; // actaully passed to update
+
+ crtn = CSSM_CSP_CreateMacContext(cspHand,
+ algorithm,
+ key,
+ &macHand);
+ if(crtn) {
+ printError("CSSM_CSP_CreateMacContext (4)", crtn);
+ return crtn;
+ }
+ crtn = CSSM_VerifyMacInit(macHand);
+ if(crtn) {
+ printError("CSSM_VerifyMacInit", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+ toMove = text->Length;
+ thisText.Data = text->Data;
+
+ while(toMove) {
+ if(multiUpdates) {
+ thisMove = genRand(1, toMove);
+ }
+ else {
+ thisMove = toMove;
+ }
+ thisText.Length = thisMove;
+ crtn = CSSM_VerifyMacUpdate(macHand,
+ &thisText,
+ 1);
+ if(crtn) {
+ printError("CSSM_VerifyMacUpdate", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+ thisText.Data += thisMove;
+ toMove -= thisMove;
+ }
+ crtn = CSSM_VerifyMacFinal(macHand, mac);
+ if(crtn != expectResult) {
+ if(crtn) {
+ printError("CSSM_VerifyMacFinal", crtn);
+ }
+ else {
+ printf("Unexpected good Staged Mac Verify\n");
+ }
+ ocrtn = CSSMERR_CSSM_INTERNAL_ERROR;
+ }
+abort:
+ crtn = CSSM_DeleteContext(macHand);
+ if(crtn) {
+ printError("CSSM_DeleteContext", crtn);
+ ocrtn = crtn;
+ }
+ return ocrtn;
+}
+
+#pragma mark --------- Digest ---------
+
+/*
+ * Digest functions
+ */
+CSSM_RETURN cspDigest(CSSM_CSP_HANDLE cspHand,
+ uint32 algorithm, // CSSM_ALGID_MD5, etc.
+ CSSM_BOOL mallocDigest, // if true and digest->Length = 0, we'll malloc
+ const CSSM_DATA *text,
+ CSSM_DATA_PTR digest)
+{
+ CSSM_CC_HANDLE digestHand;
+ CSSM_RETURN crtn;
+ CSSM_RETURN ocrtn = CSSM_OK;
+
+ crtn = CSSM_CSP_CreateDigestContext(cspHand,
+ algorithm,
+ &digestHand);
+ if(crtn) {
+ printError("CSSM_CSP_CreateDIgestContext (1)", crtn);
+ return crtn;
+ }
+ if(mallocDigest && (digest->Length == 0)) {
+ /* malloc digest - ask CSP for size */
+ CSSM_QUERY_SIZE_DATA querySize = {0, 0};
+ crtn = CSSM_QuerySize(digestHand,
+ CSSM_FALSE, // encrypt
+ 1,
+ &querySize);
+ if(crtn) {
+ printError("CSSM_QuerySize(3)", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+ if(querySize.SizeOutputBlock == 0) {
+ printf("Unknown digest size\n");
+ ocrtn = CSSMERR_CSSM_INTERNAL_ERROR;
+ goto abort;
+ }
+ digest->Data = (uint8 *)appMalloc(querySize.SizeOutputBlock, NULL);
+ if(digest->Data == NULL) {
+ printf("malloc failure\n");
+ ocrtn = CSSMERR_CSSM_MEMORY_ERROR;
+ goto abort;
+ }
+ digest->Length = querySize.SizeOutputBlock;
+ }
+ crtn = CSSM_DigestData(digestHand,
+ text,
+ 1,
+ digest);
+ if(crtn) {
+ printError("CSSM_DigestData", crtn);
+ ocrtn = crtn;
+ }
+abort:
+ crtn = CSSM_DeleteContext(digestHand);
+ if(crtn) {
+ printError("CSSM_DeleteContext", crtn);
+ ocrtn = crtn;
+ }
+ return ocrtn;
+}
+
+CSSM_RETURN cspStagedDigest(CSSM_CSP_HANDLE cspHand,
+ uint32 algorithm, // CSSM_ALGID_MD5, etc.
+ CSSM_BOOL mallocDigest, // if true and digest->Length = 0, we'll
+ // malloc
+ CSSM_BOOL multiUpdates, // false:single update, true:multi updates
+ const CSSM_DATA *text,
+ CSSM_DATA_PTR digest)
+{
+ CSSM_CC_HANDLE digestHand;
+ CSSM_RETURN crtn;
+ CSSM_RETURN ocrtn = CSSM_OK;
+ unsigned thisMove; // this update
+ unsigned toMove; // total to go
+ CSSM_DATA thisText; // actually passed to update
+
+ crtn = CSSM_CSP_CreateDigestContext(cspHand,
+ algorithm,
+ &digestHand);
+ if(crtn) {
+ printError("CSSM_CSP_CreateDigestContext (2)", crtn);
+ return crtn;
+ }
+ if(mallocDigest && (digest->Length == 0)) {
+ /* malloc digest - ask CSP for size */
+ CSSM_QUERY_SIZE_DATA querySize = {0, 0};
+ crtn = CSSM_QuerySize(digestHand,
+ CSSM_FALSE, // encrypt
+ 1,
+ &querySize);
+ if(crtn) {
+ printError("CSSM_QuerySize(4)", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+ if(querySize.SizeOutputBlock == 0) {
+ printf("Unknown digest size\n");
+ ocrtn = CSSMERR_CSSM_INTERNAL_ERROR;
+ goto abort;
+ }
+ digest->Data = (uint8 *)appMalloc(querySize.SizeOutputBlock, NULL);
+ if(digest->Data == NULL) {
+ printf("malloc failure\n");
+ ocrtn = CSSMERR_CSSM_MEMORY_ERROR;
+ goto abort;
+ }
+ digest->Length = querySize.SizeOutputBlock;
+ }
+ crtn = CSSM_DigestDataInit(digestHand);
+ if(crtn) {
+ printError("CSSM_DigestDataInit", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+ toMove = text->Length;
+ thisText.Data = text->Data;
+ while(toMove) {
+ if(multiUpdates) {
+ thisMove = genRand(1, toMove);
+ }
+ else {
+ thisMove = toMove;
+ }
+ thisText.Length = thisMove;
+ crtn = CSSM_DigestDataUpdate(digestHand,
+ &thisText,
+ 1);
+ if(crtn) {
+ printError("CSSM_DigestDataUpdate", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+ thisText.Data += thisMove;
+ toMove -= thisMove;
+ }
+ crtn = CSSM_DigestDataFinal(digestHand, digest);
+ if(crtn) {
+ printError("CSSM_DigestDataFinal", crtn);
+ ocrtn = crtn;
+ goto abort;
+ }
+abort:
+ crtn = CSSM_DeleteContext(digestHand);
+ if(crtn) {
+ printError("CSSM_DeleteContext", crtn);
+ ocrtn = crtn;
+ }
+ return ocrtn;
+}
+
+#pragma mark --------- wrap/unwrap ---------
+
+/* wrap key function. */
+CSSM_RETURN cspWrapKey(CSSM_CSP_HANDLE cspHand,
+ const CSSM_KEY *unwrappedKey,
+ const CSSM_KEY *wrappingKey,
+ CSSM_ALGORITHMS wrapAlg,
+ CSSM_ENCRYPT_MODE wrapMode,
+ CSSM_KEYBLOB_FORMAT wrapFormat, // NONE, PKCS7, PKCS8
+ CSSM_PADDING wrapPad,
+ CSSM_DATA_PTR initVector, // for some wrapping algs
+ CSSM_DATA_PTR descrData, // optional
+ CSSM_KEY_PTR wrappedKey) // RETURNED
+{
+ CSSM_CC_HANDLE ccHand;
+ CSSM_RETURN crtn;
+ CSSM_ACCESS_CREDENTIALS creds;
+
+ memset(wrappedKey, 0, sizeof(CSSM_KEY));
+ setBadKeyData(wrappedKey);
+ memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
+ /* special case for NULL wrap - no wrapping key */
+ if((wrappingKey == NULL) ||
+ (wrappingKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY)) {
+ crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
+ wrapAlg,
+ wrapMode,
+ &creds, // passPhrase,
+ wrappingKey,
+ initVector,
+ wrapPad, // Padding
+ 0, // Params
+ &ccHand);
+ }
+ else {
+ crtn = CSSM_CSP_CreateAsymmetricContext(cspHand,
+ wrapAlg,
+ &creds,
+ wrappingKey,
+ wrapPad, // padding
+ &ccHand);
+ if(crtn) {
+ printError("cspWrapKey/CreateContext", crtn);
+ return crtn;
+ }
+ if(initVector) {
+ /* manually add IV for CMS. The actual low-level encrypt doesn't
+ * use it (and must ignore it). */
+ crtn = AddContextAttribute(ccHand,
+ CSSM_ATTRIBUTE_INIT_VECTOR,
+ sizeof(CSSM_DATA),
+ CAT_Ptr,
+ initVector,
+ 0);
+ if(crtn) {
+ printError("CSSM_UpdateContextAttributes", crtn);
+ return crtn;
+ }
+ }
+ }
+ if(crtn) {
+ printError("cspWrapKey/CreateContext", crtn);
+ return crtn;
+ }
+ if(wrapFormat != CSSM_KEYBLOB_WRAPPED_FORMAT_NONE) {
+ /* only add this attribute if it's not the default */
+ CSSM_CONTEXT_ATTRIBUTE attr;
+ attr.AttributeType = CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT;
+ attr.AttributeLength = sizeof(uint32);
+ attr.Attribute.Uint32 = wrapFormat;
+ crtn = CSSM_UpdateContextAttributes(
+ ccHand,
+ 1,
+ &attr);
+ if(crtn) {
+ printError("CSSM_UpdateContextAttributes", crtn);
+ return crtn;
+ }
+ }
+ crtn = CSSM_WrapKey(ccHand,
+ &creds,
+ unwrappedKey,
+ descrData, // DescriptiveData
+ wrappedKey);
+ if(crtn != CSSM_OK) {
+ printError("CSSM_WrapKey", crtn);
+ }
+ if(CSSM_DeleteContext(ccHand)) {
+ printf("CSSM_DeleteContext failure\n");
+ }
+ return crtn;
+}
+
+/* unwrap key function. */
+CSSM_RETURN cspUnwrapKey(CSSM_CSP_HANDLE cspHand,
+ const CSSM_KEY *wrappedKey,
+ const CSSM_KEY *unwrappingKey,
+ CSSM_ALGORITHMS unwrapAlg,
+ CSSM_ENCRYPT_MODE unwrapMode,
+ CSSM_PADDING unwrapPad,
+ CSSM_DATA_PTR initVector, // for some wrapping algs
+ CSSM_KEY_PTR unwrappedKey, // RETURNED
+ CSSM_DATA_PTR descrData, // required
+ const char *keyLabel,
+ unsigned keyLabelLen)
+{
+ CSSM_CC_HANDLE ccHand;
+ CSSM_RETURN crtn;
+ CSSM_DATA labelData;
+ uint32 keyAttr;
+ CSSM_ACCESS_CREDENTIALS creds;
+
+ memset(unwrappedKey, 0, sizeof(CSSM_KEY));
+ setBadKeyData(unwrappedKey);
+ memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
+ if((unwrappingKey == NULL) ||
+ (unwrappingKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY)) {
+ crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
+ unwrapAlg,
+ unwrapMode,
+ &creds,
+ unwrappingKey,
+ initVector,
+ unwrapPad,
+ 0, // Params
+ &ccHand);
+ }
+ else {
+ crtn = CSSM_CSP_CreateAsymmetricContext(cspHand,
+ unwrapAlg,
+ &creds, // passPhrase,
+ unwrappingKey,
+ unwrapPad, // Padding
+ &ccHand);
+ if(crtn) {
+ printError("cspUnwrapKey/CreateContext", crtn);
+ return crtn;
+ }
+ if(initVector) {
+ /* manually add IV for CMS. The actual low-level encrypt doesn't
+ * use it (and must ignore it). */
+ crtn = AddContextAttribute(ccHand,
+ CSSM_ATTRIBUTE_INIT_VECTOR,
+ sizeof(CSSM_DATA),
+ CAT_Ptr,
+ initVector,
+ 0);
+ if(crtn) {
+ printError("CSSM_UpdateContextAttributes", crtn);
+ return crtn;
+ }
+ }
+ }
+ if(crtn) {
+ printError("cspUnwrapKey/CreateContext", crtn);
+ return crtn;
+ }
+ labelData.Data = (uint8 *)keyLabel;
+ labelData.Length = keyLabelLen;
+
+ /*
+ * New keyAttr - clear some old bits, make sure we ask for ref key
+ */
+ keyAttr = wrappedKey->KeyHeader.KeyAttr;
+ keyAttr &= ~(CSSM_KEYATTR_ALWAYS_SENSITIVE | CSSM_KEYATTR_NEVER_EXTRACTABLE);
+ keyAttr |= CSSM_KEYATTR_RETURN_REF;
+ crtn = CSSM_UnwrapKey(ccHand,
+ NULL, // PublicKey
+ wrappedKey,
+ wrappedKey->KeyHeader.KeyUsage,
+ keyAttr,
+ &labelData,
+ NULL, // CredAndAclEntry
+ unwrappedKey,
+ descrData); // required
+ if(crtn != CSSM_OK) {
+ printError("CSSM_UnwrapKey", crtn);
+ }
+ if(CSSM_DeleteContext(ccHand)) {
+ printf("CSSM_DeleteContext failure\n");
+ }
+ return crtn;
+}
+
+/*
+ * Simple NULL wrap to convert a reference key to a raw key.
+ */
+CSSM_RETURN cspRefKeyToRaw(
+ CSSM_CSP_HANDLE cspHand,
+ const CSSM_KEY *refKey,
+ CSSM_KEY_PTR rawKey) // init'd and RETURNED
+{
+ CSSM_DATA descData = {0, 0};
+
+ memset(rawKey, 0, sizeof(CSSM_KEY));
+ return cspWrapKey(cspHand,
+ refKey,
+ NULL, // unwrappingKey
+ CSSM_ALGID_NONE,
+ CSSM_ALGMODE_NONE,
+ CSSM_KEYBLOB_WRAPPED_FORMAT_NONE,
+ CSSM_PADDING_NONE,
+ NULL, // IV
+ &descData,
+ rawKey);
+}
+
+/*
+ * Convert ref key to raw key with specified format.
+ */
+CSSM_RETURN cspRefKeyToRawWithFormat(
+ CSSM_CSP_HANDLE cspHand,
+ const CSSM_KEY *refKey,
+ CSSM_KEYBLOB_FORMAT format,
+ CSSM_KEY_PTR rawKey) // init'd and RETURNED
+{
+ memset(rawKey, 0, sizeof(CSSM_KEY));
+ CSSM_ATTRIBUTE_TYPE attrType;
+
+ switch(refKey->KeyHeader.KeyClass) {
+ case CSSM_KEYCLASS_PUBLIC_KEY:
+ attrType = CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT;
+ break;
+ case CSSM_KEYCLASS_PRIVATE_KEY:
+ attrType = CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT;
+ break;
+ case CSSM_KEYCLASS_SESSION_KEY:
+ attrType = CSSM_ATTRIBUTE_SYMMETRIC_KEY_FORMAT;
+ break;
+ default:
+ printf("***Unknown key class\n");
+ return CSSMERR_CSP_INVALID_KEY;
+ }
+
+ CSSM_DATA descData = {0, 0};
+ CSSM_CC_HANDLE ccHand;
+ CSSM_RETURN crtn;
+// uint32 keyAttr;
+ CSSM_ACCESS_CREDENTIALS creds;
+
+ memset(rawKey, 0, sizeof(CSSM_KEY));
+ memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
+ crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
+ CSSM_ALGID_NONE,
+ CSSM_ALGMODE_NONE,
+ &creds,
+ NULL, // unwrappingKey
+ NULL, // initVector
+ CSSM_PADDING_NONE,
+ NULL, // Reserved
+ &ccHand);
+ if(crtn) {
+ printError("cspRefKeyToRawWithFormat/CreateContext", crtn);
+ return crtn;
+ }
+
+ /* Add the spec for the resulting format */
+ crtn = AddContextAttribute(ccHand,
+ attrType,
+ sizeof(uint32),
+ CAT_Uint32,
+ NULL,
+ format);
+
+ crtn = CSSM_WrapKey(ccHand,
+ &creds,
+ refKey,
+ &descData, // DescriptiveData
+ rawKey);
+ if(crtn != CSSM_OK) {
+ printError("CSSM_WrapKey", crtn);
+ }
+ if(rawKey->KeyHeader.Format != format) {
+ printf("***cspRefKeyToRawWithFormat format scewup\n");
+ crtn = CSSMERR_CSP_INTERNAL_ERROR;
+ }
+ if(CSSM_DeleteContext(ccHand)) {
+ printf("CSSM_DeleteContext failure\n");
+ }
+ return crtn;
+}
+
+/* unwrap raw key --> ref */
+CSSM_RETURN cspRawKeyToRef(
+ CSSM_CSP_HANDLE cspHand,
+ const CSSM_KEY *rawKey,
+ CSSM_KEY_PTR refKey) // init'd and RETURNED
+{
+ CSSM_DATA descData = {0, 0};
+
+ memset(refKey, 0, sizeof(CSSM_KEY));
+ return cspUnwrapKey(cspHand,
+ rawKey,
+ NULL, // unwrappingKey
+ CSSM_ALGID_NONE,
+ CSSM_ALGMODE_NONE,
+ CSSM_PADDING_NONE,
+ NULL, // init vector
+ refKey,
+ &descData,
+ "noLabel",
+ 7);
+}
+
+
+#pragma mark --------- FEE key/curve support ---------
+
+/*
+ * Generate random key size, primeType, curveType for FEE key for specified op.
+ *
+ * First just enumerate the curves we know about, with ECDSA-INcapable first
+ */
+
+typedef struct {
+ uint32 keySizeInBits;
+ uint32 primeType; // CSSM_FEE_PRIME_TYPE_xxx
+ uint32 curveType; // CSSM_FEE_CURVE_TYPE_xxx
+} feeCurveParams;
+
+#define FEE_PROTOTYPE_CURVES 0
+#if FEE_PROTOTYPE_CURVES
+/* obsolete as of 4/9/2001 */
+static feeCurveParams feeCurves[] = {
+ { 31, CSSM_FEE_PRIME_TYPE_MERSENNE, CSSM_FEE_CURVE_TYPE_MONTGOMERY },
+ { 127, CSSM_FEE_PRIME_TYPE_MERSENNE, CSSM_FEE_CURVE_TYPE_MONTGOMERY },
+ { 127, CSSM_FEE_PRIME_TYPE_GENERAL, CSSM_FEE_CURVE_TYPE_MONTGOMERY },
+ #define NUM_NON_ECDSA_CURVES 3
+
+ /* start of Weierstrass, IEEE P1363-capable curves */
+ { 31, CSSM_FEE_PRIME_TYPE_MERSENNE, CSSM_FEE_CURVE_TYPE_WEIERSTRASS },
+ { 40, CSSM_FEE_PRIME_TYPE_FEE, CSSM_FEE_CURVE_TYPE_WEIERSTRASS },
+ { 127, CSSM_FEE_PRIME_TYPE_MERSENNE, CSSM_FEE_CURVE_TYPE_WEIERSTRASS },
+ { 160, CSSM_FEE_PRIME_TYPE_FEE, CSSM_FEE_CURVE_TYPE_WEIERSTRASS },
+ { 160, CSSM_FEE_PRIME_TYPE_GENERAL, CSSM_FEE_CURVE_TYPE_WEIERSTRASS },
+ { 192, CSSM_FEE_PRIME_TYPE_FEE, CSSM_FEE_CURVE_TYPE_WEIERSTRASS },
+};
+#else /* FEE_PROTOTYPE_CURVES */
+static feeCurveParams feeCurves[] = {
+ { 31, CSSM_FEE_PRIME_TYPE_MERSENNE, CSSM_FEE_CURVE_TYPE_MONTGOMERY },
+ { 127, CSSM_FEE_PRIME_TYPE_MERSENNE, CSSM_FEE_CURVE_TYPE_MONTGOMERY },
+ #define NUM_NON_ECDSA_CURVES 2
+
+ /* start of Weierstrass, IEEE P1363-capable curves */
+ { 31, CSSM_FEE_PRIME_TYPE_MERSENNE, CSSM_FEE_CURVE_TYPE_WEIERSTRASS },
+ { 128, CSSM_FEE_PRIME_TYPE_FEE, CSSM_FEE_CURVE_TYPE_WEIERSTRASS },
+ { 161, CSSM_FEE_PRIME_TYPE_FEE, CSSM_FEE_CURVE_TYPE_WEIERSTRASS },
+ { 161, CSSM_FEE_PRIME_TYPE_GENERAL, CSSM_FEE_CURVE_TYPE_WEIERSTRASS },
+ { 192, CSSM_FEE_PRIME_TYPE_GENERAL, CSSM_FEE_CURVE_TYPE_WEIERSTRASS },
+};
+#endif /* FEE_PROTOTYPE_CURVES */
+#define NUM_FEE_CURVES (sizeof(feeCurves) / sizeof(feeCurveParams))
+
+void randFeeKeyParams(
+ CSSM_ALGORITHMS alg, // ALGID_FEED, CSSM_ALGID_FEE_MD5, etc.
+ uint32 *keySizeInBits, // RETURNED
+ uint32 *primeType, // CSSM_FEE_PRIME_TYPE_xxx, RETURNED
+ uint32 *curveType) // CSSM_FEE_CURVE_TYPE_xxx, RETURNED
+{
+ unsigned minParams;
+ unsigned die;
+ feeCurveParams *feeParams;
+
+ switch(alg) {
+ case CSSM_ALGID_SHA1WithECDSA:
+ minParams = NUM_NON_ECDSA_CURVES;
+ break;
+ default:
+ minParams = 0;
+ break;
+ }
+ die = genRand(minParams, (NUM_FEE_CURVES - 1));
+ feeParams = &feeCurves[die];
+ *keySizeInBits = feeParams->keySizeInBits;
+ *primeType = feeParams->primeType;
+ *curveType = feeParams->curveType;
+}
+
+/*
+ * Obtain strings for primeType and curveType.
+ */
+const char *primeTypeStr(uint32 primeType)
+{
+ const char *p;
+ switch(primeType) {
+ case CSSM_FEE_PRIME_TYPE_MERSENNE:
+ p = "Mersenne";
+ break;
+ case CSSM_FEE_PRIME_TYPE_FEE:
+ p = "FEE";
+ break;
+ case CSSM_FEE_PRIME_TYPE_GENERAL:
+ p = "General";
+ break;
+ case CSSM_FEE_PRIME_TYPE_DEFAULT:
+ p = "Default";
+ break;
+ default:
+ p = "***UNKNOWN***";
+ break;
+ }
+ return p;
+}
+
+const char *curveTypeStr(uint32 curveType)
+{
+ const char *c;
+ switch(curveType) {
+ case CSSM_FEE_CURVE_TYPE_DEFAULT:
+ c = "Default";
+ break;
+ case CSSM_FEE_CURVE_TYPE_MONTGOMERY:
+ c = "Montgomery";
+ break;
+ case CSSM_FEE_CURVE_TYPE_WEIERSTRASS:
+ c = "Weierstrass";
+ break;
+ default:
+ c = "***UNKNOWN***";
+ break;
+ }
+ return c;
+}
+
+/*
+ * Perform FEE Key exchange via CSSM_DeriveKey.
+ */
+#if 0
+/* Not implemented in OS X */
+CSSM_RETURN cspFeeKeyExchange(CSSM_CSP_HANDLE cspHand,
+ CSSM_KEY_PTR privKey,
+ CSSM_KEY_PTR pubKey,
+ CSSM_KEY_PTR derivedKey, // mallocd by caller
+
+ /* remaining fields apply to derivedKey */
+ uint32 keyAlg,
+ const char *keyLabel,
+ unsigned keyLabelLen,
+ uint32 keyUsage, // CSSM_KEYUSE_ENCRYPT, etc.
+ uint32 keySizeInBits)
+{
+ CSSM_CC_HANDLE dkHand;
+ CSSM_RETURN crtn;
+ CSSM_DATA labelData;
+
+ if(derivedKey == NULL) {
+ printf("cspFeeKeyExchange: no derivedKey\n");
+ return CSSMERR_CSSM_INTERNAL_ERROR;
+ }
+ if((pubKey == NULL) ||
+ (pubKey->KeyHeader.KeyClass != CSSM_KEYCLASS_PUBLIC_KEY) ||
+ (pubKey->KeyHeader.BlobType != CSSM_KEYBLOB_RAW)) {
+ printf("cspFeeKeyExchange: bad pubKey\n");
+ return CSSMERR_CSSM_INTERNAL_ERROR;
+ }
+ if((privKey == NULL) ||
+ (privKey->KeyHeader.KeyClass != CSSM_KEYCLASS_PRIVATE_KEY) ||
+ (privKey->KeyHeader.BlobType != CSSM_KEYBLOB_REFERENCE)) {
+ printf("cspFeeKeyExchange: bad privKey\n");
+ return CSSMERR_CSSM_INTERNAL_ERROR;
+ }
+ memset(derivedKey, 0, sizeof(CSSM_KEY));
+
+ crtn = CSSM_CSP_CreateDeriveKeyContext(cspHand,
+ CSSM_ALGID_FEE_KEYEXCH, // AlgorithmID
+ keyAlg, // alg of the derived key
+ keySizeInBits,
+ NULL, // access creds
+ // FIXME
+ 0, // IterationCount
+ NULL, // Salt
+ NULL, // Seed
+ NULL); // PassPhrase
+ if(dkHand == 0) {
+ printError("CSSM_CSP_CreateDeriveKeyContext");
+ return CSSM_FAIL;
+ }
+ labelData.Length = keyLabelLen;
+ labelData.Data = (uint8 *)keyLabel;
+ crtn = CSSM_DeriveKey(dkHand,
+ privKey,
+ &pubKey->KeyData, // Param - pub key blob
+ keyUsage,
+ CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE |
+ CSSM_KEYATTR_SENSITIVE,
+ &labelData,
+ derivedKey);
+
+ /* FIXME - save/restore error */
+ CSSM_DeleteContext(dkHand);
+ if(crtn) {
+ printError("CSSM_DeriveKey");
+ }
+ return crtn;
+}
+#endif
+
+#pragma mark --------- Key/DL/DB support ---------
+
+/*
+ * Add a DL/DB handle to a crypto context.
+ */
+CSSM_RETURN cspAddDlDbToContext(
+ CSSM_CC_HANDLE ccHand,
+ CSSM_DL_HANDLE dlHand,
+ CSSM_DB_HANDLE dbHand)
+{
+ CSSM_DL_DB_HANDLE dlDb = { dlHand, dbHand };
+ return AddContextAttribute(ccHand,
+ CSSM_ATTRIBUTE_DL_DB_HANDLE,
+ sizeof(CSSM_ATTRIBUTE_DL_DB_HANDLE),
+ CAT_Ptr,
+ &dlDb,
+ 0);
+}
+
+/*
+ * Common routine to do a basic DB lookup by label and key type.
+ * Query is aborted prior to exit.
+ */
+static CSSM_DB_UNIQUE_RECORD_PTR dlLookup(
+ CSSM_DL_DB_HANDLE dlDbHand,
+ const CSSM_DATA *keyLabel,
+ CT_KeyType keyType,
+ CSSM_HANDLE *resultHand, // RETURNED
+ CSSM_DATA_PTR theData, // RETURED
+ CSSM_DB_RECORDTYPE *recordType) // RETURNED
+{
+ CSSM_QUERY query;
+ CSSM_SELECTION_PREDICATE predicate;
+ CSSM_DB_UNIQUE_RECORD_PTR record = NULL;
+ CSSM_RETURN crtn;
+
+ switch(keyType) {
+ case CKT_Public:
+ query.RecordType = *recordType = CSSM_DL_DB_RECORD_PUBLIC_KEY;
+ break;
+ case CKT_Private:
+ query.RecordType = *recordType = CSSM_DL_DB_RECORD_PRIVATE_KEY;
+ break;
+ case CKT_Session:
+ query.RecordType = *recordType = CSSM_DL_DB_RECORD_SYMMETRIC_KEY;
+ break;
+ default:
+ printf("Hey bozo! Give me a valid key type!\n");
+ return NULL;
+ }
+ query.Conjunctive = CSSM_DB_NONE;
+ query.NumSelectionPredicates = 1;
+ predicate.DbOperator = CSSM_DB_EQUAL;
+
+ predicate.Attribute.Info.AttributeNameFormat =
+ CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
+ predicate.Attribute.Info.Label.AttributeName = (char *) "Label";
+ predicate.Attribute.Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
+ /* hope this cast is OK */
+ predicate.Attribute.Value = (CSSM_DATA_PTR)keyLabel;
+ query.SelectionPredicate = &predicate;
+
+ query.QueryLimits.TimeLimit = 0; // FIXME - meaningful?
+ query.QueryLimits.SizeLimit = 1; // FIXME - meaningful?
+ query.QueryFlags = CSSM_QUERY_RETURN_DATA; // FIXME - used?
+
+ crtn = CSSM_DL_DataGetFirst(dlDbHand,
+ &query,
+ resultHand,
+ NULL,
+ theData,
+ &record);
+ /* abort only on success */
+ if(crtn == CSSM_OK) {
+ crtn = CSSM_DL_DataAbortQuery(dlDbHand, *resultHand);
+ if(crtn) {
+ printError("CSSM_DL_AbortQuery", crtn);
+ return NULL;
+ }
+ }
+ return record;
+}
+
+/*
+ * Look up a key by label and type.
+ */
+CSSM_KEY_PTR cspLookUpKeyByLabel(
+ CSSM_DL_HANDLE dlHand,
+ CSSM_DB_HANDLE dbHand,
+ const CSSM_DATA *labelData,
+ CT_KeyType keyType)
+{
+ CSSM_DB_UNIQUE_RECORD_PTR record;
+ CSSM_HANDLE resultHand;
+ CSSM_DATA theData;
+ CSSM_KEY_PTR key;
+ CSSM_DB_RECORDTYPE recordType;
+ CSSM_DL_DB_HANDLE dlDbHand;
+
+ dlDbHand.DLHandle = dlHand;
+ dlDbHand.DBHandle = dbHand;
+
+ theData.Length = 0;
+ theData.Data = NULL;
+
+ record = dlLookup(dlDbHand,
+ labelData,
+ keyType,
+ &resultHand,
+ &theData,
+ &recordType);
+ if(record == NULL) {
+ //printf("cspLookUpKeyByLabel: key not found\n");
+ return NULL;
+ }
+ key = (CSSM_KEY_PTR)theData.Data;
+ CSSM_DL_FreeUniqueRecord(dlDbHand, record);
+ return key;
+}
+
+/*
+ * Delete and free a key
+ */
+CSSM_RETURN cspDeleteKey(
+ CSSM_CSP_HANDLE cspHand, // for free
+ CSSM_DL_HANDLE dlHand, // for delete
+ CSSM_DB_HANDLE dbHand, // ditto
+ const CSSM_DATA *labelData,
+ CSSM_KEY_PTR key)
+{
+ CSSM_DB_UNIQUE_RECORD_PTR record;
+ CSSM_HANDLE resultHand;
+ CT_KeyType keyType;
+ CSSM_RETURN crtn = CSSM_OK;
+ CSSM_DB_RECORDTYPE recordType;
+ CSSM_DL_DB_HANDLE dlDbHand;
+
+ if(key->KeyHeader.KeyAttr & CSSM_KEYATTR_PERMANENT) {
+ /* first do a lookup based in this key's fields */
+ switch(key->KeyHeader.KeyClass) {
+ case CSSM_KEYCLASS_PUBLIC_KEY:
+ keyType = CKT_Public;
+ break;
+ case CSSM_KEYCLASS_PRIVATE_KEY:
+ keyType = CKT_Private;
+ break;
+ case CSSM_KEYCLASS_SESSION_KEY:
+ keyType = CKT_Session;
+ break;
+ default:
+ printf("Hey bozo! Give me a valid key type!\n");
+ return -1;
+ }
+
+ dlDbHand.DLHandle = dlHand;
+ dlDbHand.DBHandle = dbHand;
+
+ record = dlLookup(dlDbHand,
+ labelData,
+ keyType,
+ &resultHand,
+ NULL, // don't want actual data
+ &recordType);
+ if(record == NULL) {
+ printf("cspDeleteKey: key not found in DL\n");
+ return CSSMERR_DL_RECORD_NOT_FOUND;
+ }
+
+ /* OK, nuke it */
+ crtn = CSSM_DL_DataDelete(dlDbHand, record);
+ if(crtn) {
+ printError("CSSM_DL_DataDelete", crtn);
+ }
+ CSSM_DL_FreeUniqueRecord(dlDbHand, record);
+ }
+
+ /* CSSM_FreeKey() should fail due to the delete, but it will
+ * still free KeyData....
+ * FIXME - we should be able to do this in this one single call - right?
+ */
+ CSSM_FreeKey(cspHand, NULL, key, CSSM_FALSE);
+
+ return crtn;
+}
+
+/*
+ * Given any key in either blob or reference format,
+ * obtain the associated SHA-1 hash.
+ */
+CSSM_RETURN cspKeyHash(
+ CSSM_CSP_HANDLE cspHand,
+ const CSSM_KEY_PTR key, /* public key */
+ CSSM_DATA_PTR *hashData) /* hash mallocd and RETURNED here */
+{
+ CSSM_CC_HANDLE ccHand;
+ CSSM_RETURN crtn;
+ CSSM_DATA_PTR dp;
+
+ *hashData = NULL;
+
+ /* validate input params */
+ if((key == NULL) ||
+ (hashData == NULL)) {
+ printf("cspKeyHash: bogus args\n");
+ return CSSMERR_CSSM_INTERNAL_ERROR;
+ }
+
+ /* cook up a context for a passthrough op */
+ crtn = CSSM_CSP_CreatePassThroughContext(cspHand,
+ key,
+ &ccHand);
+ if(ccHand == 0) {
+ printError("CSSM_CSP_CreatePassThroughContext", crtn);
+ return crtn;
+ }
+
+ /* now it's up to the CSP */
+ crtn = CSSM_CSP_PassThrough(ccHand,
+ CSSM_APPLECSP_KEYDIGEST,
+ NULL,
+ (void **)&dp);
+ if(crtn) {
+ printError("CSSM_CSP_PassThrough(PUBKEYHASH)", crtn);
+ }
+ else {
+ *hashData = dp;
+ crtn = CSSM_OK;
+ }
+ CSSM_DeleteContext(ccHand);
+ return crtn;
+}
+