X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/SecurityTests/cspxutils/utilLib/cspwrap.c diff --git a/SecurityTests/cspxutils/utilLib/cspwrap.c b/SecurityTests/cspxutils/utilLib/cspwrap.c new file mode 100644 index 00000000..0a86659e --- /dev/null +++ b/SecurityTests/cspxutils/utilLib/cspwrap.c @@ -0,0 +1,3279 @@ +/* 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 +#include +#include "cspwrap.h" +#include "common.h" +#include +#include +#include +/* MCF hack */ +// #include +#include +/* 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; +} +