#include "AppleCSPSession.h"
#include "AppleCSPUtils.h"
#include "AppleCSPKeys.h"
#include "cspdebugging.h"
#define USE_SECOND_CCHAND 0
#define REUSE_CONTEXT 1
#define VERBOSE_DEBUG 0
static const uint8 magicCmsIv[] =
{ 0x4a, 0xdd, 0xa2, 0x2c, 0x79, 0xe8, 0x21, 0x05 };
#if VERBOSE_DEBUG
static void dumpBuf(
char *title,
const CSSM_DATA *d,
uint32 maxLen)
{
unsigned i;
uint32 len;
if(title) {
printf("%s: ", title);
}
if(d == NULL) {
printf("NO DATA\n");
return;
}
printf("Total Length: %d\n ", d->Length);
len = maxLen;
if(d->Length < len) {
len = d->Length;
}
for(i=0; i<len; i++) {
printf("%02X ", d->Data[i]);
if((i % 16) == 15) {
printf("\n ");
}
}
printf("\n");
}
#else
#define dumpBuf(t, d, m)
#endif
static void serializeUint32(uint32 i, uint8 *buf)
{
*buf++ = (uint8)(i >> 24);
*buf++ = (uint8)(i >> 16);
*buf++ = (uint8)(i >> 8);
*buf = (uint8)i;
}
static uint32 deserializeUint32(const uint8 *buf) {
uint32 result;
result = ((uint32)buf[0] << 24) |
((uint32)buf[1] << 16) |
((uint32)buf[2] << 8) |
(uint32)buf[3];
return result;
}
void AppleCSPSession::WrapKeyCms(
CSSM_CC_HANDLE CCHandle,
const Context &context,
const AccessCredentials &AccessCred,
const CssmKey &UnwrappedKey,
CssmData &rawBlob,
bool allocdRawBlob, const CssmData *DescriptiveData,
CssmKey &WrappedKey,
CSSM_PRIVILEGE Privilege)
{
uint32 ddLen;
CssmData PRIVATE_KEY_BYTES;
#if !REUSE_CONTEXT
Context secondCtx(context.ContextType, context.AlgorithmType);
secondCtx.copyFrom(context, privAllocator);
#endif
dumpBuf("wrap rawBlob", &rawBlob, 24);
dumpBuf("wrap DescriptiveData", DescriptiveData, 24);
if(DescriptiveData == NULL) {
ddLen = 0;
}
else {
ddLen = DescriptiveData->Length;
}
uint32 pkbLen = 4 + ddLen + rawBlob.Length;
setUpCssmData(PRIVATE_KEY_BYTES, pkbLen, privAllocator);
uint8 *cp = PRIVATE_KEY_BYTES.Data;
serializeUint32(ddLen, cp);
cp += 4;
if(ddLen != 0) {
memcpy(cp, DescriptiveData->Data, ddLen);
cp += ddLen;
}
memcpy(cp, rawBlob.Data, rawBlob.Length);
dumpBuf("wrap PRIVATE_KEY_BYTES", &PRIVATE_KEY_BYTES, 48);
CssmData TEMP1;
CSSM_SIZE bytesEncrypted;
CssmData remData;
EncryptData(CCHandle,
context,
&PRIVATE_KEY_BYTES, 1, &TEMP1, 1, bytesEncrypted,
remData,
Privilege);
assert(remData.Length == 0);
TEMP1.Length = bytesEncrypted;
dumpBuf("wrap TEMP1", &TEMP1, 48);
CssmData TEMP2;
CssmData &IV = context.get<CssmData>(CSSM_ATTRIBUTE_INIT_VECTOR,
CSSMERR_CSP_MISSING_ATTR_INIT_VECTOR);
setUpCssmData(TEMP2, IV.Length + TEMP1.Length, privAllocator);
memcpy(TEMP2.Data, IV.Data, IV.Length);
memcpy(TEMP2.Data + IV.Length, TEMP1.Data, TEMP1.Length);
dumpBuf("wrap TEMP2", &TEMP2, 56);
CssmData TEMP3;
setUpCssmData(TEMP3, TEMP2.Length, privAllocator);
uint8 *cp2 = TEMP2.Data + TEMP2.Length - 1;
cp = TEMP3.Data;
for(uint32 i=0; i<TEMP2.Length; i++) {
*cp++ = *cp2--;
}
dumpBuf("wrap TEMP3", &TEMP3, 64);
#if REUSE_CONTEXT
CssmData &IV2 = context.get<CssmData>(CSSM_ATTRIBUTE_INIT_VECTOR,
CSSMERR_CSP_MISSING_ATTR_INIT_VECTOR);
#else
CssmData &IV2 = secondCtx.get<CssmData>(CSSM_ATTRIBUTE_INIT_VECTOR,
CSSMERR_CSP_MISSING_ATTR_INIT_VECTOR);
#endif
uint8 *savedIV = IV2.Data;
uint32 savedIVLen = IV2.Length;
IV2.Data = (uint8 *)magicCmsIv;
IV2.Length = 8;
CssmData &outBlob = CssmData::overlay(WrappedKey.KeyData);
outBlob.Length = 0;
outBlob.Data = NULL;
try {
EncryptData(CCHandle,
#if REUSE_CONTEXT
context,
#else
secondCtx,
#endif
&TEMP3, 1, &outBlob, 1, bytesEncrypted,
remData,
Privilege);
}
catch (...) {
IV2.Data = savedIV;
IV2.Length = savedIVLen;
throw; }
IV2.Data = savedIV;
IV2.Length = savedIVLen;
assert(remData.Length == 0);
outBlob.Length = bytesEncrypted;
dumpBuf("wrap outBlob", &outBlob, 64);
WrappedKey.KeyHeader.BlobType = CSSM_KEYBLOB_WRAPPED;
WrappedKey.KeyHeader.WrapMode = context.getInt(CSSM_ATTRIBUTE_MODE);
WrappedKey.KeyHeader.Format = CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM;
freeCssmData(PRIVATE_KEY_BYTES, privAllocator);
freeCssmData(TEMP1, normAllocator); freeCssmData(TEMP2, privAllocator);
freeCssmData(TEMP3, privAllocator);
if(allocdRawBlob) {
freeCssmData(rawBlob, privAllocator);
}
}
#define MAX_MALLOC_SIZE 0x10000
void AppleCSPSession::UnwrapKeyCms(
CSSM_CC_HANDLE CCHandle,
const Context &Context,
const CssmKey &WrappedKey,
const CSSM_RESOURCE_CONTROL_CONTEXT *CredAndAclEntry,
CssmKey &UnwrappedKey,
CssmData &DescriptiveData,
CSSM_PRIVILEGE Privilege,
cspKeyStorage keyStorage)
{
const CssmData &wrappedBlob = CssmData::overlay(WrappedKey.KeyData);
dumpBuf("unwrap inBlob", &wrappedBlob, 64);
CssmData &IV1 = Context.get<CssmData>(CSSM_ATTRIBUTE_INIT_VECTOR,
CSSMERR_CSP_MISSING_ATTR_INIT_VECTOR);
uint8 *savedIV = IV1.Data;
uint32 savedIvLen = IV1.Length;
IV1.Data = (uint8 *)magicCmsIv;
IV1.Length = 8;
CssmData TEMP3;
CSSM_SIZE bytesDecrypted;
CssmData remData;
try {
DecryptData(CCHandle,
Context,
&wrappedBlob, 1, &TEMP3, 1, bytesDecrypted,
remData,
Privilege);
}
catch(...) {
IV1.Data = savedIV;
IV1.Length = savedIvLen;
throw;
}
IV1.Data = savedIV;
IV1.Length = savedIvLen;
assert(remData.Length == 0);
TEMP3.Length = bytesDecrypted;
dumpBuf("unwrap TEMP3", &TEMP3, 64);
CssmData TEMP2;
setUpCssmData(TEMP2, TEMP3.Length, privAllocator);
uint8 *src = TEMP3.Data + TEMP3.Length - 1;
uint8 *dst = TEMP2.Data;
for(uint32 i=0; i<TEMP2.Length; i++) {
*dst++ = *src--;
}
dumpBuf("unwrap TEMP2", &TEMP2, 64);
if(TEMP2.Length <= 8) {
dprintf0("UnwrapKeyCms: short TEMP2\n");
CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
}
CssmData IV2;
CssmData TEMP1;
setUpCssmData(IV2, 8, privAllocator);
setUpCssmData(TEMP1, TEMP2.Length - 8, privAllocator);
memcpy(IV2.Data, TEMP2.Data, 8);
memcpy(TEMP1.Data, TEMP2.Data + 8, TEMP1.Length);
dumpBuf("unwrap TEMP1", &TEMP1, 48);
IV1 = IV2;
CssmData PRIVATE_KEY_BYTES;
try {
DecryptData(CCHandle,
Context,
&TEMP1, 1, &PRIVATE_KEY_BYTES, 1, bytesDecrypted,
remData,
Privilege);
}
catch(...) {
IV1.Data = savedIV;
IV1.Length = savedIvLen;
throw;
}
IV1.Data = savedIV;
assert(remData.Length == 0);
PRIVATE_KEY_BYTES.Length = bytesDecrypted;
dumpBuf("unwrap PRIVATE_KEY_BYTES", &PRIVATE_KEY_BYTES, 64);
if(PRIVATE_KEY_BYTES.Length < 4) {
dprintf0("UnwrapKeyCms: short PRIVATE_KEY_BYTES\n");
CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
}
uint8 *cp1 = PRIVATE_KEY_BYTES.Data;
uint32 ddLen = deserializeUint32(cp1);
cp1 += 4;
if(ddLen > MAX_MALLOC_SIZE) {
dprintf0("UnwrapKeyCms: preposterous ddLen in PRIVATE_KEY_BYTES\n");
CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
}
setUpCssmData(DescriptiveData, ddLen, normAllocator);
memcpy(DescriptiveData.Data, cp1, ddLen);
cp1 += ddLen;
uint32 outBlobLen = PRIVATE_KEY_BYTES.Length - ddLen - 4;
if(ddLen > MAX_MALLOC_SIZE) {
dprintf0("UnwrapKeyCms: preposterous outBlobLen in PRIVATE_KEY_BYTES\n");
CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
}
CssmData &outBlob = CssmData::overlay(UnwrappedKey.KeyData);
setUpCssmData(outBlob, outBlobLen, normAllocator);
memcpy(outBlob.Data, cp1, outBlobLen);
UnwrappedKey.KeyHeader.BlobType = CSSM_KEYBLOB_RAW;
UnwrappedKey.KeyHeader.Format = inferFormat(UnwrappedKey);
if(keyStorage == CKS_Ref) {
BinaryKey *binKey = NULL;
CSPKeyInfoProvider *provider = infoProvider(UnwrappedKey);
CssmKey *paramKey = Context.get<CssmKey>(CSSM_ATTRIBUTE_PARAM_KEY);
provider->CssmKeyToBinary(paramKey, UnwrappedKey.KeyHeader.KeyAttr, &binKey);
addRefKey(*binKey, UnwrappedKey);
delete provider;
}
freeCssmData(PRIVATE_KEY_BYTES, normAllocator); freeCssmData(TEMP1, privAllocator);
freeCssmData(IV2, privAllocator);
freeCssmData(TEMP2, privAllocator);
freeCssmData(TEMP3, normAllocator);
}