#include <Security/cssmapple.h>
#include <Security/cssm.h>
#include "cspwrap.h"
#include "common.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <MacTypes.h>
#ifndef NULL
#define NULL ((void *)0)
#endif
#ifndef MAX
#define MAX(a,b) ((a > b) ? a : b)
#define MIN(a,b) ((a < b) ? a : b)
#endif
#pragma mark --------- Key Generation ---------
#define FEE_PRIV_DATA_SIZE 20
#define RSA_WEAK_KEYS 0
static void setBadKeyData(
CSSM_KEY_PTR key)
{
key->KeyData.Data = (uint8 *)0xeaaaeaaa; key->KeyData.Length = 1; }
CSSM_RETURN cspGenKeyPair(CSSM_CSP_HANDLE cspHand,
uint32 algorithm,
const char *keyLabel,
unsigned keyLabelLen,
uint32 keySize, CSSM_KEY_PTR pubKey, CSSM_BOOL pubIsRef, uint32 pubKeyUsage, CSSM_KEYBLOB_FORMAT pubFormat, CSSM_KEY_PTR privKey, CSSM_BOOL privIsRef, uint32 privKeyUsage, CSSM_KEYBLOB_FORMAT privFormat, CSSM_BOOL genSeed) {
CSSM_RETURN crtn;
CSSM_CC_HANDLE ccHand;
CSSM_DATA privData = {0, NULL}; 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);
}
switch(algorithm) {
case CSSM_ALGID_FEE:
if(genSeed) {
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;
}
break;
case CSSM_ALGID_RSA:
break;
case CSSM_ALGID_DSA:
break;
case CSSM_ALGID_ECDSA:
break;
default:
printf("cspGenKeyPair: Unknown algorithm\n");
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, NULL, NULL, NULL, NULL, &ccHand);
if(crtn) {
printError("CSSM_CSP_CreateKeyGenContext", crtn);
ocrtn = crtn;
goto abort;
}
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;
}
switch(algorithm) {
case CSSM_ALGID_RSA:
#if RSA_WEAK_KEYS
{
crtn = AddContextAttribute(ccHand,
CSSM_ATTRIBUTE_MODE,
sizeof(uint32),
CAT_Uint32,
NULL,
CSSM_ALGMODE_CUSTOM);
if(crtn) {
printError("CSSM_UpdateContextAttributes", crtn);
return crtn;
}
}
#endif break;
case CSSM_ALGID_DSA:
{
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;
}
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), 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, NULL, privKey);
if(crtn) {
printError("CSSM_GenerateKeyPair", crtn);
ocrtn = crtn;
goto abort;
}
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;
}
CSSM_RETURN cspGenFEEKeyPair(CSSM_CSP_HANDLE cspHand,
const char *keyLabel,
unsigned keyLabelLen,
uint32 keySize, uint32 primeType, uint32 curveType, CSSM_KEY_PTR pubKey, CSSM_BOOL pubIsRef, uint32 pubKeyUsage, CSSM_KEYBLOB_FORMAT pubFormat, CSSM_KEY_PTR privKey, CSSM_BOOL privIsRef, uint32 privKeyUsage, CSSM_KEYBLOB_FORMAT privFormat, const CSSM_DATA *seedData) {
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;
if(seedData) {
privCData.Param = *((CSSM_DATA_PTR)seedData);
privCData.Callback = NULL;
privCDataPtr = &privCData;
}
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, NULL, NULL, NULL, NULL, &ccHand);
if(crtn) {
printError("CSSM_CSP_CreateKeyGenContext", crtn);
ocrtn = crtn;
goto abort;
}
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(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), 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, NULL, privKey);
if(crtn) {
printError("CSSM_GenerateKeyPair", crtn);
ocrtn = crtn;
goto abort;
}
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;
}
CSSM_RETURN cspGenDSAKeyPair(CSSM_CSP_HANDLE cspHand,
const char *keyLabel,
unsigned keyLabelLen,
uint32 keySize, CSSM_KEY_PTR pubKey, CSSM_BOOL pubIsRef, uint32 pubKeyUsage, CSSM_KEYBLOB_FORMAT pubFormat, CSSM_KEY_PTR privKey, CSSM_BOOL privIsRef, uint32 privKeyUsage, CSSM_KEYBLOB_FORMAT privFormat, CSSM_BOOL genParams,
CSSM_DATA_PTR paramData) {
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, NULL, NULL, NULL, paramData,
&ccHand);
if(crtn) {
printError("CSSM_CSP_CreateKeyGenContext", crtn);
ocrtn = crtn;
goto abort;
}
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) {
CSSM_DATA dummy = {0, NULL};
crtn = CSSM_GenerateAlgorithmParams(ccHand,
keySize, &dummy);
if(crtn) {
printError("CSSM_GenerateAlgorithmParams", crtn);
return crtn;
}
appFreeCssmData(&dummy, CSSM_FALSE);
}
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), 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, NULL, privKey);
if(crtn) {
printError("CSSM_GenerateKeyPair", crtn);
ocrtn = crtn;
goto abort;
}
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;
}
CSSM_KEY_PTR cspGenSymKey(CSSM_CSP_HANDLE cspHand,
uint32 alg,
const char *keyLabel,
unsigned keyLabelLen,
uint32 keyUsage, 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, NULL, NULL, NULL, NULL, NULL, &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, 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;
}
CSSM_KEY_PTR cspDeriveKey(CSSM_CSP_HANDLE cspHand,
uint32 deriveAlg, uint32 keyAlg, const char *keyLabel,
unsigned keyLabelLen,
uint32 keyUsage, uint32 keySizeInBits,
CSSM_BOOL isRefKey,
CSSM_DATA_PTR password, CSSM_DATA_PTR salt, uint32 iterationCnt, CSSM_DATA_PTR initVector) {
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, iterationCnt,
salt,
NULL, &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;
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, symKey);
if(crtn) {
printError("CSSM_DeriveKey", crtn);
goto errorOut;
}
#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;
}
CSSM_RETURN cspGenSymKeyWithBits(
CSSM_CSP_HANDLE cspHand,
CSSM_ALGORITHMS keyAlg,
CSSM_KEYUSE keyUsage,
const CSSM_DATA *keyBits,
unsigned keySizeInBytes,
CSSM_KEY_PTR refKey) {
CSSM_KEY rawKey;
CSSM_KEYHEADER_PTR hdr = &rawKey.KeyHeader;
CSSM_RETURN crtn;
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);
crtn = cspRawKeyToRef(cspHand, &rawKey, refKey);
appFreeCssmData(&rawKey.KeyData, CSSM_FALSE);
return crtn;
}
CSSM_RETURN cspFreeKey(CSSM_CSP_HANDLE cspHand,
CSSM_KEY_PTR key)
{
CSSM_RETURN crtn;
crtn = CSSM_FreeKey(cspHand,
NULL, key,
CSSM_FALSE); if(crtn) {
printError("CSSM_FreeKey", crtn);
}
return crtn;
}
uint32 randKeySizeBits(uint32 alg,
opType op) {
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 ; 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:
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:
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:
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);
if(alg != CSSM_ALGID_RC2) {
size &= ~0x7;
}
switch(alg) {
case CSSM_ALGID_RSA:
size &= ~(16 - 1);
break;
case CSSM_ALGID_DSA:
size &= ~(64 - 1);
break;
default:
break;
}
return size;
}
#pragma mark --------- Encrypt/Decrypt ---------
#define EFFECTIVE_SIZE_VIA_PARAMS 0
CSSM_CC_HANDLE genCryptHandle(CSSM_CSP_HANDLE cspHand,
uint32 algorithm, uint32 mode, CSSM_PADDING padding, const CSSM_KEY *key0,
const CSSM_KEY *key1, const CSSM_DATA *iv, uint32 effectiveKeySizeInBits, uint32 rounds) {
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: crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
algorithm,
mode,
NULL, key0,
iv, padding,
NULL, &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, key0,
padding,
&cryptHand);
if(crtn) {
printError("CSSM_CSP_CreateAsymmetricContext", crtn);
return 0;
}
if(key1 != NULL) {
crtn = AddContextAttribute(cryptHand,
CSSM_ATTRIBUTE_PUBLIC_KEY,
sizeof(CSSM_KEY), CAT_Ptr,
key1,
0);
if(crtn) {
printError("AddContextAttribute", crtn);
return 0;
}
}
if(mode != CSSM_ALGMODE_NONE) {
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
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, uint32 mode, CSSM_PADDING padding, const CSSM_KEY *key, const CSSM_KEY *pubKey, uint32 effectiveKeySizeInBits, uint32 rounds, const CSSM_DATA *iv, const CSSM_DATA *ptext,
CSSM_DATA_PTR ctext, CSSM_BOOL mallocCtext) {
CSSM_CC_HANDLE cryptHand;
CSSM_RETURN crtn;
CSSM_SIZE bytesEncrypted;
CSSM_DATA remData = {0, NULL};
CSSM_RETURN ocrtn = CSSM_OK;
unsigned origCtextLen; 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, 1,
&querySize);
if(crtn) {
printError("CSSM_QuerySize", crtn);
ocrtn = crtn;
goto abort;
}
if(querySize.SizeOutputBlock == 0) {
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) {
if((remData.Length != 0) && mallocCtext) {
if(bytesEncrypted > origCtextLen) {
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 {
memmove(ctext->Data+ctext->Length, remData.Data, remData.Length);
}
ctext->Length = bytesEncrypted;
}
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, uint32 mode, CSSM_PADDING padding, const CSSM_KEY *key, const CSSM_KEY *pubKey, uint32 effectiveKeySizeInBits, uint32 cipherBlockSize, uint32 rounds, const CSSM_DATA *iv, const CSSM_DATA *ptext,
CSSM_DATA_PTR ctext, CSSM_BOOL multiUpdates) {
CSSM_CC_HANDLE cryptHand;
CSSM_RETURN crtn;
CSSM_SIZE bytesEncrypted; CSSM_SIZE bytesEncryptedTotal = 0;
CSSM_RETURN ocrtn = CSSM_OK; unsigned toMove; unsigned thisMove; CSSM_DATA thisPtext; CSSM_DATA ctextWork; CSSM_QUERY_SIZE_DATA querySize;
uint8 *origCtext; unsigned origCtextLen; 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;
}
}
querySize.SizeInputBlock = ptext->Length;
crtn = CSSM_QuerySize(cryptHand,
CSSM_TRUE, 1,
&querySize);
if(crtn) {
printError("CSSM_QuerySize(1)", crtn);
ocrtn = CSSMERR_CSP_INTERNAL_ERROR;
goto abort;
}
if(querySize.SizeOutputBlock == 0) {
printf("***cspStagedEncrypt: warning: cipherTextSize unknown; aborting\n");
ocrtn = CSSMERR_CSP_INTERNAL_ERROR;
goto abort;
}
else {
origCtextLen = querySize.SizeOutputBlock;
if(algorithm == CSSM_ALGID_ASC) {
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 {
thisMove = toMove;
}
thisPtext.Length = thisMove;
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;
}
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);
}
}
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) {
CSSM_FREE(ctextWork.Data);
}
ctext->Data = origCtext;
ctext->Length = bytesEncryptedTotal;
abort:
crtn = CSSM_DeleteContext(cryptHand);
if(crtn) {
printError("CSSM_DeleteContext", crtn);
ocrtn = crtn;
}
if(restoreErr) {
ocrtn = savedErr;
}
return ocrtn;
}
CSSM_RETURN cspDecrypt(CSSM_CSP_HANDLE cspHand,
uint32 algorithm, uint32 mode, CSSM_PADDING padding, const CSSM_KEY *key, const CSSM_KEY *pubKey, uint32 effectiveKeySizeInBits, uint32 rounds, const CSSM_DATA *iv, const CSSM_DATA *ctext,
CSSM_DATA_PTR ptext, CSSM_BOOL mallocPtext) {
CSSM_CC_HANDLE cryptHand;
CSSM_RETURN crtn;
CSSM_RETURN ocrtn = CSSM_OK;
CSSM_SIZE bytesDecrypted;
CSSM_DATA remData = {0, NULL};
unsigned origPtextLen;
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, 1,
&querySize);
if(crtn) {
printError("CSSM_QuerySize", crtn);
ocrtn = crtn;
goto abort;
}
if(querySize.SizeOutputBlock == 0) {
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) {
if((remData.Length != 0) && mallocPtext) {
if(bytesDecrypted > origPtextLen) {
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 {
memmove(ptext->Data + ptext->Length,
remData.Data, remData.Length);
}
ptext->Length = bytesDecrypted;
}
ptext->Length = bytesDecrypted;
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, uint32 mode, CSSM_PADDING padding, const CSSM_KEY *key, const CSSM_KEY *pubKey, uint32 effectiveKeySizeInBits, uint32 cipherBlockSize, uint32 rounds, const CSSM_DATA *iv, const CSSM_DATA *ctext,
CSSM_DATA_PTR ptext, CSSM_BOOL multiUpdates) {
CSSM_CC_HANDLE cryptHand;
CSSM_RETURN crtn;
CSSM_SIZE bytesDecrypted; CSSM_SIZE bytesDecryptedTotal = 0;
CSSM_RETURN ocrtn = CSSM_OK; unsigned toMove; unsigned thisMove; CSSM_DATA thisCtext; CSSM_DATA ptextWork; CSSM_QUERY_SIZE_DATA querySize;
uint8 *origPtext; unsigned origPtextLen;
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;
}
}
querySize.SizeInputBlock = ctext->Length;
crtn = CSSM_QuerySize(cryptHand,
CSSM_FALSE, 1,
&querySize);
if(crtn) {
printError("CSSM_QuerySize(1)", crtn);
ocrtn = crtn;
goto abort;
}
if(querySize.SizeOutputBlock == 0) {
printf("***warning: cspStagedDecrypt: plainTextSize unknown; aborting\n");
ocrtn = CSSMERR_CSP_INTERNAL_ERROR;
goto abort;
}
else {
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 {
thisMove = toMove;
}
thisCtext.Length = thisMove;
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;
}
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);
}
}
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) {
CSSM_FREE(ptextWork.Data);
}
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 ---------
CSSM_RETURN cspSign(CSSM_CSP_HANDLE cspHand,
uint32 algorithm, CSSM_KEY_PTR key, const CSSM_DATA *text,
CSSM_DATA_PTR sig) {
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;
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, text,
&digest);
if(crtn) {
return crtn;
}
ptext = &digest;
}
else {
ptext = text;
}
crtn = CSSM_CSP_CreateSignatureContext(cspHand,
algorithm,
NULL, 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;
}
CSSM_RETURN cspStagedSign(CSSM_CSP_HANDLE cspHand,
uint32 algorithm, CSSM_KEY_PTR key, const CSSM_DATA *text,
CSSM_BOOL multiUpdates, CSSM_DATA_PTR sig) {
CSSM_CC_HANDLE sigHand;
CSSM_RETURN crtn;
CSSM_RETURN ocrtn = CSSM_OK;
unsigned thisMove; unsigned toMove; CSSM_DATA thisText; crtn = CSSM_CSP_CreateSignatureContext(cspHand,
algorithm,
NULL, 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;
}
CSSM_RETURN cspSigVerify(CSSM_CSP_HANDLE cspHand,
uint32 algorithm, CSSM_KEY_PTR key, const CSSM_DATA *text,
const CSSM_DATA *sig,
CSSM_RETURN expectResult) {
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;
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, text,
&digest);
if(crtn) {
return crtn;
}
ptext = &digest;
}
else {
ptext = text;
}
crtn = CSSM_CSP_CreateSignatureContext(cspHand,
algorithm,
NULL, 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;
}
CSSM_RETURN cspStagedSigVerify(CSSM_CSP_HANDLE cspHand,
uint32 algorithm, CSSM_KEY_PTR key, const CSSM_DATA *text,
const CSSM_DATA *sig,
CSSM_BOOL multiUpdates, CSSM_RETURN expectResult) {
CSSM_CC_HANDLE sigHand;
CSSM_RETURN crtn;
CSSM_RETURN ocrtn = CSSM_OK;
unsigned thisMove; unsigned toMove; CSSM_DATA thisText; crtn = CSSM_CSP_CreateSignatureContext(cspHand,
algorithm,
NULL, 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;
}
CSSM_RETURN cspGenMac(CSSM_CSP_HANDLE cspHand,
uint32 algorithm, CSSM_KEY_PTR key, const CSSM_DATA *text,
CSSM_DATA_PTR mac) {
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;
}
CSSM_RETURN cspStagedGenMac(CSSM_CSP_HANDLE cspHand,
uint32 algorithm, CSSM_KEY_PTR key, const CSSM_DATA *text,
CSSM_BOOL mallocMac, CSSM_BOOL multiUpdates, CSSM_DATA_PTR mac) {
CSSM_CC_HANDLE macHand;
CSSM_RETURN crtn;
CSSM_RETURN ocrtn = CSSM_OK;
unsigned thisMove; unsigned toMove; CSSM_DATA thisText;
crtn = CSSM_CSP_CreateMacContext(cspHand,
algorithm,
key,
&macHand);
if(crtn) {
printError("CSSM_CSP_CreateMacContext (2)", crtn);
return crtn;
}
if(mallocMac && (mac->Length == 0)) {
CSSM_QUERY_SIZE_DATA querySize = {0, 0};
crtn = CSSM_QuerySize(macHand,
CSSM_TRUE, 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_KEY_PTR key, const CSSM_DATA *text,
const CSSM_DATA_PTR mac,
CSSM_RETURN expectResult) {
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;
}
CSSM_RETURN cspStagedMacVerify(CSSM_CSP_HANDLE cspHand,
uint32 algorithm, CSSM_KEY_PTR key, const CSSM_DATA *text,
const CSSM_DATA_PTR mac,
CSSM_BOOL multiUpdates, CSSM_RETURN expectResult) {
CSSM_CC_HANDLE macHand;
CSSM_RETURN crtn;
CSSM_RETURN ocrtn = CSSM_OK;
unsigned thisMove; unsigned toMove; CSSM_DATA thisText;
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 ---------
CSSM_RETURN cspDigest(CSSM_CSP_HANDLE cspHand,
uint32 algorithm, CSSM_BOOL mallocDigest, 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)) {
CSSM_QUERY_SIZE_DATA querySize = {0, 0};
crtn = CSSM_QuerySize(digestHand,
CSSM_FALSE, 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_BOOL mallocDigest, CSSM_BOOL multiUpdates, const CSSM_DATA *text,
CSSM_DATA_PTR digest)
{
CSSM_CC_HANDLE digestHand;
CSSM_RETURN crtn;
CSSM_RETURN ocrtn = CSSM_OK;
unsigned thisMove; unsigned toMove; CSSM_DATA thisText;
crtn = CSSM_CSP_CreateDigestContext(cspHand,
algorithm,
&digestHand);
if(crtn) {
printError("CSSM_CSP_CreateDigestContext (2)", crtn);
return crtn;
}
if(mallocDigest && (digest->Length == 0)) {
CSSM_QUERY_SIZE_DATA querySize = {0, 0};
crtn = CSSM_QuerySize(digestHand,
CSSM_FALSE, 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 ---------
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, CSSM_PADDING wrapPad,
CSSM_DATA_PTR initVector, CSSM_DATA_PTR descrData, CSSM_KEY_PTR wrappedKey) {
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));
if((wrappingKey == NULL) ||
(wrappingKey->KeyHeader.KeyClass == CSSM_KEYCLASS_SESSION_KEY)) {
crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
wrapAlg,
wrapMode,
&creds, wrappingKey,
initVector,
wrapPad, 0, &ccHand);
}
else {
crtn = CSSM_CSP_CreateAsymmetricContext(cspHand,
wrapAlg,
&creds,
wrappingKey,
wrapPad, &ccHand);
if(crtn) {
printError("cspWrapKey/CreateContext", crtn);
return crtn;
}
if(initVector) {
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) {
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, wrappedKey);
if(crtn != CSSM_OK) {
printError("CSSM_WrapKey", crtn);
}
if(CSSM_DeleteContext(ccHand)) {
printf("CSSM_DeleteContext failure\n");
}
return crtn;
}
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, CSSM_KEY_PTR unwrappedKey, CSSM_DATA_PTR descrData, 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, &ccHand);
}
else {
crtn = CSSM_CSP_CreateAsymmetricContext(cspHand,
unwrapAlg,
&creds, unwrappingKey,
unwrapPad, &ccHand);
if(crtn) {
printError("cspUnwrapKey/CreateContext", crtn);
return crtn;
}
if(initVector) {
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;
keyAttr = wrappedKey->KeyHeader.KeyAttr;
keyAttr &= ~(CSSM_KEYATTR_ALWAYS_SENSITIVE | CSSM_KEYATTR_NEVER_EXTRACTABLE);
keyAttr |= CSSM_KEYATTR_RETURN_REF;
crtn = CSSM_UnwrapKey(ccHand,
NULL, wrappedKey,
wrappedKey->KeyHeader.KeyUsage,
keyAttr,
&labelData,
NULL, unwrappedKey,
descrData); if(crtn != CSSM_OK) {
printError("CSSM_UnwrapKey", crtn);
}
if(CSSM_DeleteContext(ccHand)) {
printf("CSSM_DeleteContext failure\n");
}
return crtn;
}
CSSM_RETURN cspRefKeyToRaw(
CSSM_CSP_HANDLE cspHand,
const CSSM_KEY *refKey,
CSSM_KEY_PTR rawKey) {
CSSM_DATA descData = {0, 0};
memset(rawKey, 0, sizeof(CSSM_KEY));
return cspWrapKey(cspHand,
refKey,
NULL, CSSM_ALGID_NONE,
CSSM_ALGMODE_NONE,
CSSM_KEYBLOB_WRAPPED_FORMAT_NONE,
CSSM_PADDING_NONE,
NULL, &descData,
rawKey);
}
CSSM_RETURN cspRefKeyToRawWithFormat(
CSSM_CSP_HANDLE cspHand,
const CSSM_KEY *refKey,
CSSM_KEYBLOB_FORMAT format,
CSSM_KEY_PTR rawKey) {
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;
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, NULL, CSSM_PADDING_NONE,
NULL, &ccHand);
if(crtn) {
printError("cspRefKeyToRawWithFormat/CreateContext", crtn);
return crtn;
}
crtn = AddContextAttribute(ccHand,
attrType,
sizeof(uint32),
CAT_Uint32,
NULL,
format);
crtn = CSSM_WrapKey(ccHand,
&creds,
refKey,
&descData, 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;
}
CSSM_RETURN cspRawKeyToRef(
CSSM_CSP_HANDLE cspHand,
const CSSM_KEY *rawKey,
CSSM_KEY_PTR refKey) {
CSSM_DATA descData = {0, 0};
memset(refKey, 0, sizeof(CSSM_KEY));
return cspUnwrapKey(cspHand,
rawKey,
NULL, CSSM_ALGID_NONE,
CSSM_ALGMODE_NONE,
CSSM_PADDING_NONE,
NULL, refKey,
&descData,
"noLabel",
7);
}
#pragma mark --------- FEE key/curve support ---------
typedef struct {
uint32 keySizeInBits;
uint32 primeType; uint32 curveType; } feeCurveParams;
#define FEE_PROTOTYPE_CURVES 0
#if 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 },
{ 127, CSSM_FEE_PRIME_TYPE_GENERAL, CSSM_FEE_CURVE_TYPE_MONTGOMERY },
#define NUM_NON_ECDSA_CURVES 3
{ 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
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
{ 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
#define NUM_FEE_CURVES (sizeof(feeCurves) / sizeof(feeCurveParams))
void randFeeKeyParams(
CSSM_ALGORITHMS alg, uint32 *keySizeInBits, uint32 *primeType, uint32 *curveType) {
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;
}
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;
}
#if 0
CSSM_RETURN cspFeeKeyExchange(CSSM_CSP_HANDLE cspHand,
CSSM_KEY_PTR privKey,
CSSM_KEY_PTR pubKey,
CSSM_KEY_PTR derivedKey,
uint32 keyAlg,
const char *keyLabel,
unsigned keyLabelLen,
uint32 keyUsage, 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, keyAlg, keySizeInBits,
NULL, 0, NULL, NULL, NULL); if(dkHand == 0) {
printError("CSSM_CSP_CreateDeriveKeyContext");
return CSSM_FAIL;
}
labelData.Length = keyLabelLen;
labelData.Data = (uint8 *)keyLabel;
crtn = CSSM_DeriveKey(dkHand,
privKey,
&pubKey->KeyData, keyUsage,
CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE |
CSSM_KEYATTR_SENSITIVE,
&labelData,
derivedKey);
CSSM_DeleteContext(dkHand);
if(crtn) {
printError("CSSM_DeriveKey");
}
return crtn;
}
#endif
#pragma mark --------- Key/DL/DB support ---------
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);
}
static CSSM_DB_UNIQUE_RECORD_PTR dlLookup(
CSSM_DL_DB_HANDLE dlDbHand,
const CSSM_DATA *keyLabel,
CT_KeyType keyType,
CSSM_HANDLE *resultHand, CSSM_DATA_PTR theData, CSSM_DB_RECORDTYPE *recordType) {
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;
predicate.Attribute.Value = (CSSM_DATA_PTR)keyLabel;
query.SelectionPredicate = &predicate;
query.QueryLimits.TimeLimit = 0; query.QueryLimits.SizeLimit = 1; query.QueryFlags = CSSM_QUERY_RETURN_DATA;
crtn = CSSM_DL_DataGetFirst(dlDbHand,
&query,
resultHand,
NULL,
theData,
&record);
if(crtn == CSSM_OK) {
crtn = CSSM_DL_DataAbortQuery(dlDbHand, *resultHand);
if(crtn) {
printError("CSSM_DL_AbortQuery", crtn);
return NULL;
}
}
return record;
}
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) {
return NULL;
}
key = (CSSM_KEY_PTR)theData.Data;
CSSM_DL_FreeUniqueRecord(dlDbHand, record);
return key;
}
CSSM_RETURN cspDeleteKey(
CSSM_CSP_HANDLE cspHand, CSSM_DL_HANDLE dlHand, CSSM_DB_HANDLE dbHand, 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) {
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, &recordType);
if(record == NULL) {
printf("cspDeleteKey: key not found in DL\n");
return CSSMERR_DL_RECORD_NOT_FOUND;
}
crtn = CSSM_DL_DataDelete(dlDbHand, record);
if(crtn) {
printError("CSSM_DL_DataDelete", crtn);
}
CSSM_DL_FreeUniqueRecord(dlDbHand, record);
}
CSSM_FreeKey(cspHand, NULL, key, CSSM_FALSE);
return crtn;
}
CSSM_RETURN cspKeyHash(
CSSM_CSP_HANDLE cspHand,
const CSSM_KEY_PTR key,
CSSM_DATA_PTR *hashData)
{
CSSM_CC_HANDLE ccHand;
CSSM_RETURN crtn;
CSSM_DATA_PTR dp;
*hashData = NULL;
if((key == NULL) ||
(hashData == NULL)) {
printf("cspKeyHash: bogus args\n");
return CSSMERR_CSSM_INTERNAL_ERROR;
}
crtn = CSSM_CSP_CreatePassThroughContext(cspHand,
key,
&ccHand);
if(ccHand == 0) {
printError("CSSM_CSP_CreatePassThroughContext", crtn);
return crtn;
}
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;
}