#define ALLOW_PUB_KEY_WRAP 1
#include "AppleCSPSession.h"
#include "AppleCSPUtils.h"
#ifdef USE_SNACC
#include "pkcs_7_8.h"
#endif
#include "cspdebugging.h"
void AppleCSPSession::WrapKey(
CSSM_CC_HANDLE CCHandle,
const Context &Context,
const AccessCredentials &AccessCred,
const CssmKey &UnwrappedKey,
const CssmData *DescriptiveData,
CssmKey &WrappedKey,
CSSM_PRIVILEGE Privilege)
{
CssmKey::Header &wrappedHdr = WrappedKey.header();
bool isNullWrap = false;
CssmKey *wrappingKey = NULL;
CSSM_KEYBLOB_FORMAT wrapFormat;
switch(UnwrappedKey.keyClass()) {
case CSSM_KEYCLASS_PUBLIC_KEY:
case CSSM_KEYCLASS_PRIVATE_KEY:
case CSSM_KEYCLASS_SESSION_KEY:
break;
default:
CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
}
wrappingKey = Context.get<CssmKey>(CSSM_ATTRIBUTE_KEY);
if(wrappingKey == NULL) {
if((Context.algorithm() == CSSM_ALGID_NONE) &&
(Context.type() == CSSM_ALGCLASS_SYMMETRIC)) {
isNullWrap = true;
}
else {
errorLog0("WrapKey: missing wrapping key\n");
CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_KEY);
}
}
if(isNullWrap) {
wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_NONE;
}
else {
#if !ALLOW_PUB_KEY_WRAP
if(UnwrappedKey.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY) {
CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
}
#endif
cspValidateIntendedKeyUsage(&wrappingKey->KeyHeader, CSSM_KEYUSE_WRAP);
CSSM_CONTEXT_TYPE wrapType;
switch(wrappingKey->KeyHeader.KeyClass) {
case CSSM_KEYCLASS_PUBLIC_KEY:
case CSSM_KEYCLASS_PRIVATE_KEY:
wrapType = CSSM_ALGCLASS_ASYMMETRIC;
break;
case CSSM_KEYCLASS_SESSION_KEY:
wrapType = CSSM_ALGCLASS_SYMMETRIC;
break;
default:
errorLog0("WrapKey: bad class of wrappingKey\n");
CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_KEY);
}
if(wrapType != Context.type()) {
errorLog0("WrapKey: mismatch wrappingKey/contextType\n");
CssmError::throwMe(CSSMERR_CSP_INVALID_CONTEXT);
}
if(Context.algorithm() == CSSM_ALGID_NONE) {
errorLog0("WrapKey: null wrap alg, non-null key\n");
CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
}
wrapFormat = Context.getInt(CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT);
if(wrapFormat == CSSM_KEYBLOB_WRAPPED_FORMAT_NONE) {
if(wrapType == CSSM_ALGCLASS_ASYMMETRIC) {
#ifdef USE_SNACC
wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8;
#else
wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM;
#endif
}
else {
CASSERT(wrapType == CSSM_ALGCLASS_SYMMETRIC);
if((wrappingKey->algorithm() == CSSM_ALGID_3DES_3KEY) &&
(UnwrappedKey.algorithm() == CSSM_ALGID_3DES_3KEY)) {
wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM;
}
else {
#ifdef USE_SNACC
wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7;
#else
wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM;
#endif
}
}
}
}
switch(wrapFormat) {
#if 0
case CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7:
case CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8:
#endif
case CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM:
break;
case CSSM_KEYBLOB_WRAPPED_FORMAT_NONE:
if(isNullWrap) {
break;
}
default:
dprintf1("KeyWrap: invalid wrapFormat (%d)\n", (int)wrapFormat);
CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_WRAPPED_KEY_FORMAT);
}
CssmData rawBlob;
bool allocdRawBlob = false;
CSSM_KEYBLOB_FORMAT rawFormat;
switch(UnwrappedKey.blobType()) {
case CSSM_KEYBLOB_RAW:
rawBlob = CssmData::overlay(UnwrappedKey.KeyData);
rawFormat = UnwrappedKey.blobFormat();
break;
case CSSM_KEYBLOB_REFERENCE:
{
BinaryKey &binKey = lookupRefKey(UnwrappedKey);
if(isNullWrap) {
CSSM_KEYATTR_FLAGS keyAttr = binKey.mKeyHeader.KeyAttr;
if((keyAttr & CSSM_KEYATTR_SENSITIVE) ||
!(keyAttr & CSSM_KEYATTR_EXTRACTABLE)) {
CssmError::throwMe(
CSSMERR_CSP_INVALID_KEYATTR_MASK);
}
}
rawFormat = requestedKeyFormat(Context, UnwrappedKey);
binKey.generateKeyBlob(privAllocator,
rawBlob,
rawFormat);
}
allocdRawBlob = true; break;
default:
errorLog0("WrapKey: bad unwrappedKey BlobType\n");
CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
}
const CssmKey::Header &unwrappedHdr = UnwrappedKey.header();
setKeyHeader(wrappedHdr,
plugin.myGuid(),
unwrappedHdr.algorithm(), unwrappedHdr.keyClass(), unwrappedHdr.KeyAttr,
unwrappedHdr.KeyUsage);
wrappedHdr.LogicalKeySizeInBits = unwrappedHdr.LogicalKeySizeInBits;
wrappedHdr.WrapAlgorithmId = Context.algorithm(); wrappedHdr.Format = wrapFormat;
if(isNullWrap) {
wrappedHdr.BlobType = CSSM_KEYBLOB_RAW;
}
else {
wrappedHdr.BlobType = CSSM_KEYBLOB_WRAPPED;
}
if(!isNullWrap && (wrapFormat == CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM)) {
try {
WrapKeyCms(CCHandle,
Context,
AccessCred,
UnwrappedKey,
rawBlob,
allocdRawBlob,
DescriptiveData,
WrappedKey,
Privilege);
}
catch(...) {
if(allocdRawBlob) {
freeCssmData(rawBlob, privAllocator);
}
throw;
}
if(allocdRawBlob) {
freeCssmData(rawBlob, privAllocator);
}
return;
}
CssmData encryptedBlob;
CssmData remData;
WrappedKey.KeyData.Data = NULL; WrappedKey.KeyData.Length = 0;
try {
if(isNullWrap) {
copyCssmData(rawBlob,
CssmData::overlay(WrappedKey.KeyData),
normAllocator);
wrappedHdr.Format = rawFormat;
}
#ifdef USE_SNACC
else {
uint32 bytesEncrypted;
EncryptData(CCHandle,
Context,
&rawBlob, 1, &encryptedBlob, 1, bytesEncrypted,
remData,
Privilege);
assert(remData.Length == 0);
encryptedBlob.Length = bytesEncrypted;
if(wrapFormat == CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7) {
cspEncodePkcs7(Context.algorithm(),
Context.getInt(CSSM_ATTRIBUTE_MODE),
encryptedBlob,
CssmData::overlay(WrappedKey.KeyData),
normAllocator);
}
else {
CASSERT(wrapFormat == CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8);
cspEncodePkcs8(Context.algorithm(),
Context.getInt(CSSM_ATTRIBUTE_MODE),
encryptedBlob,
CssmData::overlay(WrappedKey.KeyData),
normAllocator);
}
wrappedHdr.BlobType = CSSM_KEYBLOB_WRAPPED;
wrappedHdr.WrapMode = Context.getInt(
CSSM_ATTRIBUTE_MODE);
}
#endif
}
catch (...) {
errorLog0("WrapKey: EncryptData() threw exception\n");
if(allocdRawBlob) {
freeCssmData(rawBlob, privAllocator);
}
freeCssmData(encryptedBlob, normAllocator);
freeCssmData(remData,normAllocator);
throw;
}
if(allocdRawBlob) {
freeCssmData(rawBlob, privAllocator);
}
freeCssmData(encryptedBlob, normAllocator);
freeCssmData(remData, normAllocator);
}
void AppleCSPSession::UnwrapKey(
CSSM_CC_HANDLE CCHandle,
const Context &Context,
const CssmKey *PublicKey,
const CssmKey &WrappedKey,
uint32 KeyUsage,
uint32 KeyAttr,
const CssmData *KeyLabel,
const CSSM_RESOURCE_CONTROL_CONTEXT *CredAndAclEntry,
CssmKey &UnwrappedKey,
CssmData &DescriptiveData,
CSSM_PRIVILEGE Privilege)
{
bool isNullUnwrap = false;
CssmKey *unwrappingKey = NULL;
cspKeyType keyType; CSSM_KEYBLOB_FORMAT wrapFormat = WrappedKey.blobFormat();
unwrappingKey = Context.get<CssmKey>(CSSM_ATTRIBUTE_KEY);
if(unwrappingKey == NULL) {
if((Context.algorithm() == CSSM_ALGID_NONE) &&
(Context.type() == CSSM_ALGCLASS_SYMMETRIC)) {
isNullUnwrap = true;
}
else {
errorLog0("UnwrapKey: missing wrapping key\n");
CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_KEY);
}
}
if(!isNullUnwrap) {
CSSM_CONTEXT_TYPE unwrapType;
switch(unwrappingKey->KeyHeader.KeyClass) {
case CSSM_KEYCLASS_PUBLIC_KEY:
case CSSM_KEYCLASS_PRIVATE_KEY:
unwrapType = CSSM_ALGCLASS_ASYMMETRIC;
break;
case CSSM_KEYCLASS_SESSION_KEY:
unwrapType = CSSM_ALGCLASS_SYMMETRIC;
break;
default:
errorLog0("UnwrapKey: bad class of wrappingKey\n");
CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_KEY);
}
if(unwrapType != Context.type()) {
errorLog0("UnwrapKey: mismatch unwrappingKey/contextType\n");
CssmError::throwMe(CSSMERR_CSP_INVALID_CONTEXT);
}
if(Context.algorithm() == CSSM_ALGID_NONE) {
errorLog0("UnwrapKey: null wrap alg, non-null key\n");
CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
}
cspValidateIntendedKeyUsage(&unwrappingKey->KeyHeader, CSSM_KEYUSE_UNWRAP);
}
switch(WrappedKey.keyClass()) {
case CSSM_KEYCLASS_PUBLIC_KEY:
#if !ALLOW_PUB_KEY_WRAP
if(!isNullUnwrap) {
errorLog0("UnwrapKey: unwrap of public key illegal\n");
CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
}
#endif
keyType = CKT_Public;
break;
case CSSM_KEYCLASS_PRIVATE_KEY:
keyType = CKT_Private;
break;
case CSSM_KEYCLASS_SESSION_KEY:
keyType = CKT_Session;
break;
default:
CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
}
if(isNullUnwrap) {
if(WrappedKey.blobType() != CSSM_KEYBLOB_RAW) {
errorLog0("UnwrapKey: expected raw blobType\n");
CssmError::throwMe(CSSMERR_CSP_KEY_BLOB_TYPE_INCORRECT);
}
}
else {
if(WrappedKey.blobType() != CSSM_KEYBLOB_WRAPPED) {
errorLog0("UnwrapKey: expected wrapped blobType\n");
CssmError::throwMe(CSSMERR_CSP_KEY_BLOB_TYPE_INCORRECT);
}
}
cspKeyStorage keyStorage = cspParseKeyAttr(keyType, KeyAttr);
switch(keyStorage) {
case CKS_Ref:
case CKS_Data:
break; default:
CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
}
cspValidateKeyUsageBits(keyType, KeyUsage);
CssmKey::Header &unwrappedHdr = UnwrappedKey.header();
const CssmKey::Header &wrappedHdr = WrappedKey.header();
setKeyHeader(unwrappedHdr,
plugin.myGuid(),
wrappedHdr.algorithm(), wrappedHdr.keyClass(), KeyAttr & ~KEY_ATTR_RETURN_MASK,
KeyUsage);
unwrappedHdr.LogicalKeySizeInBits = wrappedHdr.LogicalKeySizeInBits;
unwrappedHdr.KeyUsage = wrappedHdr.KeyUsage;
UnwrappedKey.KeyData.Data = NULL; UnwrappedKey.KeyData.Length = 0;
if(!isNullUnwrap) {
switch(wrapFormat) {
#ifdef USE_SNACC
case CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7:
case CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8:
break;
#endif
case CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM:
UnwrapKeyCms(CCHandle,
Context,
WrappedKey,
CredAndAclEntry,
UnwrappedKey,
DescriptiveData,
Privilege,
keyStorage);
return;
default:
CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_WRAPPED_KEY_FORMAT);
}
}
CssmData decodedBlob;
CssmData remData;
try {
if(isNullUnwrap) {
copyData(WrappedKey.KeyData,
UnwrappedKey.KeyData,
normAllocator);
unwrappedHdr.BlobType = CSSM_KEYBLOB_RAW;
unwrappedHdr.Format = wrapFormat;
}
#ifdef USE_SNACC
else {
CSSM_KEYBLOB_FORMAT rawFormat;
if(wrapFormat == CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7) {
cspDecodePkcs7(WrappedKey,
decodedBlob,
rawFormat,
normAllocator);
}
else {
cspDecodePkcs8(WrappedKey,
decodedBlob,
rawFormat,
normAllocator);
}
uint32 bytesDecrypted;
CssmData *unwrapData =
CssmData::overlay(&UnwrappedKey.KeyData);
DecryptData(CCHandle,
Context,
&decodedBlob, 1, unwrapData, 1, bytesDecrypted,
remData,
Privilege);
assert(remData.Length == 0);
UnwrappedKey.KeyData.Length = bytesDecrypted;
unwrappedHdr.BlobType = CSSM_KEYBLOB_RAW;
unwrappedHdr.Format = rawFormat;
}
#endif
}
catch (...) {
errorLog0("UnwrapKey: DecryptData() threw exception\n");
freeCssmData(decodedBlob, normAllocator);
freeCssmData(remData, normAllocator);
throw;
}
freeCssmData(decodedBlob, normAllocator);
freeCssmData(remData, normAllocator);
if(keyStorage == CKS_Ref) {
BinaryKey *binKey = NULL;
CSPKeyInfoProvider *provider = infoProvider(UnwrappedKey);
provider->CssmKeyToBinary(&binKey);
addRefKey(*binKey, UnwrappedKey);
delete provider;
}
}