/* 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; }