void
SDCSPSession::GenerateKey(CSSM_CC_HANDLE ccHandle,
						  const Context &context,
						  uint32 keyUsage,
						  uint32 keyAttr,
						  const CssmData *keyLabel,
						  const CSSM_RESOURCE_CONTROL_CONTEXT *credAndAclEntry,
						  CssmKey &key,
						  CSSM_PRIVILEGE privilege)
{
	CSSM_DB_HANDLE database = getDatabase(context);
	validateKeyAttr(keyAttr);
	const AccessCredentials *cred = NULL;
	const AclEntryInput *owner = NULL;
	if (credAndAclEntry)
	{
		cred = AccessCredentials::overlay(credAndAclEntry->AccessCred);
		owner = &AclEntryInput::overlay(credAndAclEntry->InitialAclEntry);
	}

	KeyHandle keyHandle;
	clientSession().generateKey(ClientSession::toIPCHandle(database), context, keyUsage,
								keyAttr, cred, owner, keyHandle, key.header());
	makeReferenceKey(keyHandle, key, database, keyAttr, keyLabel);
}
void
SDCSPSession::GenerateKeyPair(CSSM_CC_HANDLE ccHandle,
							  const Context &context,
							  uint32 publicKeyUsage,
							  uint32 publicKeyAttr,
							  const CssmData *publicKeyLabel,
							  CssmKey &publicKey,
							  uint32 privateKeyUsage,
							  uint32 privateKeyAttr,
							  const CssmData *privateKeyLabel,
							  const CSSM_RESOURCE_CONTROL_CONTEXT *credAndAclEntry,
							  CssmKey &privateKey,
							  CSSM_PRIVILEGE privilege)
{
	CSSM_DB_HANDLE database = getDatabase(context);
	validateKeyAttr(publicKeyAttr);
	validateKeyAttr(privateKeyAttr);
	const AccessCredentials *cred = NULL;
	const AclEntryInput *owner = NULL;
	if (credAndAclEntry)
	{
		cred = AccessCredentials::overlay(credAndAclEntry->AccessCred);
		owner = &AclEntryInput::overlay(credAndAclEntry->InitialAclEntry);
	}

	/* 
	 * Public keys must be extractable in the clear - that's the Apple
	 * policy. The raw CSP is unable to enforce the extractable
	 * bit since it always sees that as true (it's managed and forced
	 * true by the SecurityServer). So...
	 */
	if(!(publicKeyAttr & CSSM_KEYATTR_EXTRACTABLE)) {
			CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
	}
	KeyHandle pubKeyHandle, privKeyHandle;
	clientSession().generateKey(ClientSession::toIPCHandle(database), context,
							   publicKeyUsage, publicKeyAttr,
							   privateKeyUsage, privateKeyAttr,
							   cred, owner,
							   pubKeyHandle, publicKey.header(),
							   privKeyHandle, privateKey.header());
	makeReferenceKey(privKeyHandle, privateKey, database, privateKeyAttr,
					 privateKeyLabel);
	// @@@ What if this throws, we need to free privateKey.
	makeReferenceKey(pubKeyHandle, publicKey, database, publicKeyAttr,
					 publicKeyLabel);
}
void
SDCSPSession::DeriveKey(CSSM_CC_HANDLE ccHandle,
						const Context &context,
						CssmData &param,
						uint32 keyUsage,
						uint32 keyAttr,
						const CssmData *keyLabel,
						const CSSM_RESOURCE_CONTROL_CONTEXT *credAndAclEntry,
						CssmKey &derivedKey)
{
	CSSM_DB_HANDLE database = getDatabase(context);
	validateKeyAttr(keyAttr);
	const AccessCredentials *cred = NULL;
	const AclEntryInput *owner = NULL;
	if (credAndAclEntry)
	{
		cred = AccessCredentials::overlay(credAndAclEntry->AccessCred);
		owner = &AclEntryInput::overlay(credAndAclEntry->InitialAclEntry);
	}

	/* optional BaseKey */
 	const CssmKey *keyInContext =
		context.get<const CssmKey>(CSSM_ATTRIBUTE_KEY);
	KeyHandle contextKeyHandle =
		keyInContext ? lookupKey(*keyInContext).keyHandle() : noKey;
	KeyHandle keyHandle;
	switch(context.algorithm()) {
	case CSSM_ALGID_KEYCHAIN_KEY:
		{
			// special interpretation: take DLDBHandle -> DbHandle from params
			clientSession().extractMasterKey(ClientSession::toIPCHandle(database), context,
				(DbHandle)getDatabase(param.interpretedAs<CSSM_DL_DB_HANDLE>(CSSMERR_CSP_INVALID_ATTR_DL_DB_HANDLE)),
				keyUsage, keyAttr, cred, owner, keyHandle, derivedKey.header());
		}
		break;
	default:
            clientSession().deriveKey(ClientSession::toIPCHandle(database), context, contextKeyHandle, keyUsage,
					keyAttr, param, cred, owner, keyHandle, derivedKey.header());
		break;
	}
	makeReferenceKey(keyHandle, derivedKey, database, keyAttr, keyLabel);
}
//
// Turn raw keybits into a symmetric key in the CSP
//
CssmClient::Key DatabaseCryptoCore::makeRawKey(void *data, size_t length,
    CSSM_ALGORITHMS algid, CSSM_KEYUSE usage)
{
    // build a fake key
    CssmKey key;
    key.header().BlobType = CSSM_KEYBLOB_RAW;
    key.header().Format = CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING;
    key.header().AlgorithmId = algid;
    key.header().KeyClass = CSSM_KEYCLASS_SESSION_KEY;
    key.header().KeyUsage = usage;
    key.header().KeyAttr = 0;
    key.KeyData = CssmData(data, length);
    
    // unwrap it into the CSP (but keep it raw)
    UnwrapKey unwrap(Server::csp(), CSSM_ALGID_NONE);
    CssmKey unwrappedKey;
    CssmData descriptiveData;
    unwrap(key,
        KeySpec(CSSM_KEYUSE_ANY, CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE),
        unwrappedKey, &descriptiveData, NULL);
    return CssmClient::Key(Server::csp(), unwrappedKey);
}
void
SDCSPSession::UnwrapKey(CSSM_CC_HANDLE CCHandle,
						const Context &context,
						const CssmKey *PublicKey,
						const CssmWrappedKey &WrappedKey,
						uint32 KeyUsage,
						uint32 KeyAttr,
						const CssmData *KeyLabel,
						const CSSM_RESOURCE_CONTROL_CONTEXT *CredAndAclEntry,
						CssmKey &UnwrappedKey,
						CssmData &DescriptiveData,
						CSSM_PRIVILEGE Privilege)
{
	CSSM_DB_HANDLE database = getDatabase(context);
	validateKeyAttr(KeyAttr);
	const AccessCredentials *cred = NULL;
	const AclEntryInput *owner = NULL;
	if (CredAndAclEntry)
	{
		cred = AccessCredentials::overlay(CredAndAclEntry->AccessCred);
		owner = &AclEntryInput::overlay(CredAndAclEntry->InitialAclEntry);
	}

	KeyHandle publicKey = noKey;
	if (PublicKey)
	{
		if (PublicKey->blobType() == CSSM_KEYBLOB_RAW)
		{
			// @@@ We need to unwrap the publicKey into the SecurityServer
			// before continuing
			CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
		}
		else
			publicKey = lookupKey(*PublicKey).keyHandle();
	}

	// @@@ Deal with permanent keys
 	const CssmKey *keyInContext =
		context.get<const CssmKey>(CSSM_ATTRIBUTE_KEY);

	KeyHandle contextKeyHandle =
		keyInContext ? lookupKey(*keyInContext).keyHandle() : noKey;

	KeyHandle unwrappedKeyHandle;
	clientSession().unwrapKey(ClientSession::toIPCHandle(database), context, contextKeyHandle,
							  publicKey, WrappedKey, KeyUsage, KeyAttr,
							  cred, owner, DescriptiveData, unwrappedKeyHandle,
							  UnwrappedKey.header(), *this);	
	makeReferenceKey(unwrappedKeyHandle, UnwrappedKey, database, KeyAttr,
					 KeyLabel);
}
Exemplo n.º 6
0
// Constructor for a Security Server generated key.
SDKey::SDKey(SDCSPSession &session, KeyHandle hKey, CssmKey &ioKey,
			 CSSM_DB_HANDLE inDBHandle, uint32 inKeyAttr,
			 const CssmData *inKeyLabel)
: ReferencedKey(session.mSDCSPDLSession),
mAllocator(session), mKeyHandle(hKey),
mClientSession(session.clientSession())
{
	CssmKey::Header &header = ioKey.header();
#if 0
	if (inKeyAttr & CSSM_KEYATTR_PERMANENT)
	{
		if (!inDBHandle)
			CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_DL_DB_HANDLE);

		// EncodeKey and store it in the db.
		CssmDataContainer blob(mAllocator);
		clientSession().encodeKey(keyHandle, blob);

		assert(header.HeaderVersion == CSSM_KEYHEADER_VERSION);
		switch (header.KeyClass)
		{
		case CSSM_KEYCLASS_PUBLIC_KEY:
			mRecordType = CSSM_DL_DB_RECORD_PUBLIC_KEY;
			break;
		case CSSM_KEYCLASS_PRIVATE_KEY:
			mRecordType = CSSM_DL_DB_RECORD_PRIVATE_KEY;
			break;
		case CSSM_KEYCLASS_SESSION_KEY:
			mRecordType = CSSM_DL_DB_RECORD_SYMMETRIC_KEY;
			break;
		default:
			CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
		}

		CssmData label;
		if (inKeyLabel)
			label = *inKeyLabel;

		CssmData none;
		// We store the keys real CSP guid on disk
		CssmGuidData creatorGuid(header.CspId);
		CssmDateData startDate(header.StartDate);
		CssmDateData endDate(header.EndDate);

		DbAttributes attributes(inDBHandle);
		attributes.recordType(mRecordType);
		attributes.add(KeySchema::KeyClass, mRecordType);
		attributes.add(KeySchema::PrintName, label);
		attributes.add(KeySchema::Alias, none);
		attributes.add(KeySchema::Permanent,
					   header.attribute(CSSM_KEYATTR_PERMANENT));
		attributes.add(KeySchema::Private,
					   header.attribute(CSSM_KEYATTR_PRIVATE));
		attributes.add(KeySchema::Modifiable,
					   header.attribute(CSSM_KEYATTR_MODIFIABLE));
		attributes.add(KeySchema::Label, label);
		attributes.add(KeySchema::ApplicationTag, none);
		attributes.add(KeySchema::KeyCreator, creatorGuid);
		attributes.add(KeySchema::KeyType, header.AlgorithmId);
		attributes.add(KeySchema::KeySizeInBits, header.LogicalKeySizeInBits);
		// @@@ Get the real effective key size.
		attributes.add(KeySchema::EffectiveKeySize, header.LogicalKeySizeInBits);
		attributes.add(KeySchema::StartDate, startDate);
		attributes.add(KeySchema::EndDate, endDate);
		attributes.add(KeySchema::Sensitive,
					   header.attribute(CSSM_KEYATTR_SENSITIVE));
		attributes.add(KeySchema::AlwaysSensitive,
					   header.attribute(CSSM_KEYATTR_ALWAYS_SENSITIVE));
		attributes.add(KeySchema::Extractable,
					   header.attribute(CSSM_KEYATTR_EXTRACTABLE));
		attributes.add(KeySchema::NeverExtractable,
					   header.attribute(CSSM_KEYATTR_NEVER_EXTRACTABLE));
		attributes.add(KeySchema::Encrypt,
					   header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_ENCRYPT));
		attributes.add(KeySchema::Decrypt,
					   header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_DECRYPT));
		attributes.add(KeySchema::Derive,
					   header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_DERIVE));
		attributes.add(KeySchema::Sign,
					   header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_SIGN));
		attributes.add(KeySchema::Verify,
					   header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_VERIFY));
		attributes.add(KeySchema::SignRecover,
					   header.useFor(CSSM_KEYUSE_ANY
									 | CSSM_KEYUSE_SIGN_RECOVER));
		attributes.add(KeySchema::VerifyRecover,
					   header.useFor(CSSM_KEYUSE_ANY
									 | CSSM_KEYUSE_VERIFY_RECOVER));
		attributes.add(KeySchema::Wrap,
					   header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_WRAP));
		attributes.add(KeySchema::Unwrap,
					   header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_UNWRAP));

		// @@@ Fixme
		mUniqueId = inDBHandle->insert(mRecordType, &attributes, &blob,
										 true);
	}

#endif
	header.cspGuid(session.plugin.myGuid()); // Set the csp guid to me.
	makeReferenceKey(mAllocator, keyReference(), ioKey);
}
Exemplo n.º 7
0
// Constructor for a key retrived from a Db.
SDKey::SDKey(SDDLSession &session, CssmKey &ioKey, KeyHandle hKey, CSSM_DB_HANDLE inDBHandle,
			 RecordHandle record, CSSM_DB_RECORDTYPE recordType,
			 CssmData &keyBlob)
: ReferencedKey(session.mSDCSPDLSession),
mAllocator(session.allocator()), mKeyHandle(hKey), mRecord(record),
mRecordType(recordType),
mClientSession(session.clientSession())
{
	CssmKey::Header &header = ioKey.header();
#if 0
	memset(&header, 0, sizeof(header)); // Clear key header

	if (!mUniqueId || !mUniqueId->database())
		CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR);

	header.HeaderVersion = CSSM_KEYHEADER_VERSION;
	switch (mRecordType)
	{
	case CSSM_DL_DB_RECORD_PUBLIC_KEY:
		header.KeyClass = CSSM_KEYCLASS_PUBLIC_KEY;
		break;
	case CSSM_DL_DB_RECORD_PRIVATE_KEY:
		header.KeyClass = CSSM_KEYCLASS_PRIVATE_KEY;
		break;
	case CSSM_DL_DB_RECORD_SYMMETRIC_KEY:
		header.KeyClass = CSSM_KEYCLASS_SESSION_KEY;
		break;
	default:
		CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
	}

	DbAttributes attributes(mUniqueId->database());
	attributes.recordType(mRecordType);
	attributes.add(KeySchema::KeyClass);			// 0
	attributes.add(KeySchema::Permanent);			// 1
	attributes.add(KeySchema::Private);			// 2
	attributes.add(KeySchema::Modifiable);			// 3
	attributes.add(KeySchema::KeyCreator);			// 4
	attributes.add(KeySchema::KeyType);			// 5
	attributes.add(KeySchema::KeySizeInBits);		// 6
	attributes.add(KeySchema::StartDate);			// 7
	attributes.add(KeySchema::EndDate);			// 8
	attributes.add(KeySchema::Sensitive);			// 9
	attributes.add(KeySchema::AlwaysSensitive);	// 10
	attributes.add(KeySchema::Extractable);		// 11
	attributes.add(KeySchema::NeverExtractable);	// 12
	attributes.add(KeySchema::Encrypt);			// 13
	attributes.add(KeySchema::Decrypt);			// 14
	attributes.add(KeySchema::Derive);				// 15
	attributes.add(KeySchema::Sign);				// 16
	attributes.add(KeySchema::Verify);				// 17
	attributes.add(KeySchema::SignRecover);		// 18
	attributes.add(KeySchema::VerifyRecover);		// 19
	attributes.add(KeySchema::Wrap);				// 20
	attributes.add(KeySchema::Unwrap);				// 21

	mUniqueId->get(&attributes, NULL);

	// Assert that the mRecordType matches the KeyClass attribute.
	if (mRecordType != uint32(attributes[0]))
		CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);

	header.AlgorithmId = attributes[5]; // KeyType
    header.LogicalKeySizeInBits = attributes[6]; // KeySizeInBits

	if (attributes[1]) header.setAttribute(CSSM_KEYATTR_PERMANENT);
	if (attributes[2]) header.setAttribute(CSSM_KEYATTR_PRIVATE);
	if (attributes[3]) header.setAttribute(CSSM_KEYATTR_MODIFIABLE);
	if (attributes[9]) header.setAttribute(CSSM_KEYATTR_SENSITIVE);
	if (attributes[11]) header.setAttribute(CSSM_KEYATTR_EXTRACTABLE);
	if (attributes[10]) header.setAttribute(CSSM_KEYATTR_ALWAYS_SENSITIVE);
	if (attributes[12]) header.setAttribute(CSSM_KEYATTR_NEVER_EXTRACTABLE);

	if (attributes[13]) header.usage(CSSM_KEYUSE_ENCRYPT);
	if (attributes[14]) header.usage(CSSM_KEYUSE_DECRYPT);
	if (attributes[15]) header.usage(CSSM_KEYUSE_DERIVE);
	if (attributes[16]) header.usage(CSSM_KEYUSE_SIGN);
	if (attributes[17]) header.usage(CSSM_KEYUSE_VERIFY);
	if (attributes[18]) header.usage(CSSM_KEYUSE_SIGN_RECOVER);
	if (attributes[19]) header.usage(CSSM_KEYUSE_VERIFY_RECOVER);
	if (attributes[20]) header.usage(CSSM_KEYUSE_WRAP);
	if (attributes[21]) header.usage(CSSM_KEYUSE_UNWRAP);

	// If all usages are allowed set usage to CSSM_KEYUSE_ANY
	if (header.usage() == (CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT
						   | CSSM_KEYUSE_DERIVE | CSSM_KEYUSE_SIGN
						   | CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_SIGN_RECOVER
						   | CSSM_KEYUSE_VERIFY_RECOVER | CSSM_KEYUSE_WRAP
						   | CSSM_KEYUSE_UNWRAP))
		header.usage(CSSM_KEYUSE_ANY); 

	if (!attributes[7].size() || !attributes[8].size())
		CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);

    header.StartDate = attributes[7].at<CSSM_DATE>(0);
    header.EndDate = attributes[8].at<CSSM_DATE>(0);

#endif
	makeReferenceKey(mAllocator, keyReference(), ioKey);
	header.cspGuid(session.plugin.myGuid()); // Set the csp guid to me.
}
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);
	}

	/* wrapping key only required for non-NULL wrap */
	wrappingKey = Context.get<CssmKey>(CSSM_ATTRIBUTE_KEY);
	if(wrappingKey == NULL) {
		if((Context.algorithm() == CSSM_ALGID_NONE) &&
		   (Context.type() == CSSM_ALGCLASS_SYMMETRIC)) {
				// NULL wrap, OK
				isNullWrap = true;
		}
		else {
			errorLog0("WrapKey: missing wrapping key\n");
			CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_KEY);
		}
	}
	
	/*
	 * Validate misc. params as best we can
	 */
	if(isNullWrap) {
		wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_NONE;
	}
	else {
		/*
		 * Can only wrap session and private keys. 
		 */
		#if		!ALLOW_PUB_KEY_WRAP
		if(UnwrappedKey.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY) {
			CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
		}
		#endif	/* ALLOW_PUB_KEY_WRAP */
		cspValidateIntendedKeyUsage(&wrappingKey->KeyHeader, CSSM_KEYUSE_WRAP);
		cspVerifyKeyTimes(wrappingKey->KeyHeader);
		
		/*
		 * make sure wrapping key type matches context
		 */
		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);
		}

		/*
		 * Get optional wrap format, set default per incoming keys
		 * Note: no such atrribute ==> 0 ==> FORMAT_NONE, which we
		 * take to mean "use the default".
		 */
		wrapFormat = Context.getInt(CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT);
		if(wrapFormat == CSSM_KEYBLOB_WRAPPED_FORMAT_NONE) {
			/* figure out a default based on unwrapped key */
			switch(UnwrappedKey.keyClass()) {
				case CSSM_KEYCLASS_SESSION_KEY:
					wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7;
					break;
				case CSSM_KEYCLASS_PUBLIC_KEY:
					wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM; 
					break;
				case CSSM_KEYCLASS_PRIVATE_KEY:
					switch(UnwrappedKey.algorithm()) {
						case CSSM_ALGID_FEE:
							wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM; 
							break;
						default:
							wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8; 
							break;
					}
					break;
				default:
					/* NOT REACHED - checked above */
					break;
			}
		}		/* no format present or FORMAT_NONE */
	}
	
	/* make sure we have a valid format here */
	switch(wrapFormat) {
		case CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7:
			if(UnwrappedKey.keyClass() != CSSM_KEYCLASS_SESSION_KEY) {
				/* this wrapping style only for symmetric keys */
				CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
			}
			break;
		case CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8:
		case CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSL:
			if(UnwrappedKey.keyClass() != CSSM_KEYCLASS_PRIVATE_KEY) {
				/* these wrapping styles only for private keys */
				CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
			}
			break;
		case CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM:
			/* no restrictions (well AES can't be the wrap alg but that will 
			 * be caught later */
			break;
		case CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSH1:
			/* RSA private key, reference format, only */
			if(UnwrappedKey.keyClass() != CSSM_KEYCLASS_PRIVATE_KEY) {
				CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
			}
			if(UnwrappedKey.algorithm() != CSSM_ALGID_RSA) {
				CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
			}
			if(UnwrappedKey.blobType() != CSSM_KEYBLOB_REFERENCE) {
				CssmError::throwMe(CSSMERR_CSP_KEY_BLOB_TYPE_INCORRECT);
			}
			break;
		case CSSM_KEYBLOB_WRAPPED_FORMAT_NONE:
			if(isNullWrap) {
				/* only time this is OK */
				break;
			}
			/* else fall thru */
		default:
			dprintf1("KeyWrap: invalid wrapFormat (%d)\n", (int)wrapFormat);
			CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_WRAPPED_KEY_FORMAT);
	}
	/* get the blob to be wrappped */
	CssmData rawBlob;
	bool allocdRawBlob = false;
	CSSM_KEYBLOB_FORMAT rawFormat;
	
	/* 
	 * Outgoing same as incoming unless a partial key is completed during 
	 * generateKeyBlob()
	 */
	const CssmKey::Header &unwrappedHdr = UnwrappedKey.header();
	CSSM_KEYATTR_FLAGS unwrappedKeyAttrFlags = unwrappedHdr.KeyAttr;
	
	switch(UnwrappedKey.blobType()) {
		case CSSM_KEYBLOB_RAW:
			/* 
			 * Trivial case - we already have the blob.
			 * This op - wrapping a raw key - is not supported for the 
			 * CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSH1 format since that doesn't
			 * operate on a key blob.
			 */
			rawBlob = CssmData::overlay(UnwrappedKey.KeyData);
			rawFormat = UnwrappedKey.blobFormat();
			break;
		case CSSM_KEYBLOB_REFERENCE:
			/* get binary key, then get blob from it */
			{
				BinaryKey &binKey = lookupRefKey(UnwrappedKey);
				
				/*
				 * Subsequent tests for extractability: don't trust the 
				 * caller's header; use the one in the BinaryKey.
				 */
				CSSM_KEYATTR_FLAGS keyAttr = binKey.mKeyHeader.KeyAttr;
				if(!(keyAttr & CSSM_KEYATTR_EXTRACTABLE)) {
					/* this key not extractable in any form */
					CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
				}
				
				/* 
				 * CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSH1: we're ready to roll; 
				 * all we need is the reference key.
				 */
				if(wrapFormat == CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSH1) {
					break;
				}
				
				/*
				 * Null wrap - prevent caller from obtaining 
				 * clear bits if CSSM_KEYATTR_SENSITIVE
				 */
				if(isNullWrap && (keyAttr & CSSM_KEYATTR_SENSITIVE)) {
					CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
				}

				/*
				 * Special case for PKCS8 and openssl: need to get blob of a specific
				 * algorithm-dependent format. Caller can override our 
				 * preference with a 
				 * CSSM_ATTRIBUTE_{PRIVATE,PUBLIC,SESSION}_KEY_FORMAT 
				 * context attribute. 
				 */
				rawFormat = requestedKeyFormat(Context, UnwrappedKey);
				if(rawFormat == CSSM_KEYBLOB_RAW_FORMAT_NONE) {
					CSSM_ALGORITHMS keyAlg = binKey.mKeyHeader.AlgorithmId;
					switch(wrapFormat) {
						case CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8:
							rawFormat = pkcs8RawKeyFormat(keyAlg);
							break;
						case CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSL:
							rawFormat = opensslRawKeyFormat(keyAlg);
							break;
						default:
							/* punt and take default for key type */
							break;
					}
				}
	
				/* 
				 * DescriptiveData for encoding, currently only used for 
				 * SSH1 keys.
				 */
				if((DescriptiveData != NULL) && (DescriptiveData->Length != 0)) {
					binKey.descData(*DescriptiveData);
				}
				
				/* optional parameter-bearing key */
				CssmKey *paramKey = Context.get<CssmKey>(CSSM_ATTRIBUTE_PARAM_KEY);
				binKey.generateKeyBlob(privAllocator,
					rawBlob,
					rawFormat,
					*this,
					paramKey,
					unwrappedKeyAttrFlags);
			}
			allocdRawBlob = true;		// remember - we need to free
			break;
			
		default:
			errorLog0("WrapKey: bad unwrappedKey BlobType\n");
			CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
	}

	/*
	 * Prepare outgoing header.
	 */
	setKeyHeader(wrappedHdr,
		plugin.myGuid(),
		unwrappedHdr.algorithm(),		// same as incoming 
		unwrappedHdr.keyClass(),		// same as incoming
		unwrappedKeyAttrFlags,
		unwrappedHdr.KeyUsage);
	wrappedHdr.LogicalKeySizeInBits = unwrappedHdr.LogicalKeySizeInBits;
	wrappedHdr.WrapAlgorithmId = Context.algorithm(); 	// true for null 
														// and non-Null 
	wrappedHdr.StartDate = unwrappedHdr.StartDate;
	wrappedHdr.EndDate = unwrappedHdr.EndDate;
	wrappedHdr.Format = wrapFormat;
	if(isNullWrap) {
		wrappedHdr.BlobType = CSSM_KEYBLOB_RAW;
	}
	else {
		wrappedHdr.BlobType = CSSM_KEYBLOB_WRAPPED;
	}
	
	/* 
	 * special cases - break out here for Apple Custom and OpenSSHv1  
	 */
	if(!isNullWrap) {
		switch(wrapFormat) {
			case 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;
			case CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSH1:
			{
				/*
				 * 1. We don't have to worry about allocdRawBlob since this 
				 *    operation only works on reference keys and we did not
				 *    obtain the raw blob from the BinaryKey. 
				 * 2. This is a redundant lookupRefKey, I know, but since
				 *    that returns a reference, it would just be too messy to have
				 *    the previous call be in the same scope as this.
				 */
				BinaryKey &binKey = lookupRefKey(UnwrappedKey);
				WrapKeyOpenSSH1(CCHandle,
					Context,
					AccessCred,
					binKey,
					rawBlob,
					allocdRawBlob,
					DescriptiveData,
					WrappedKey,
					Privilege);
				return;
			}
			default:
				/* proceed to encrypt blob */
				break;
		}
	}	/* !isNullWrap */

	
	/*
	 * Generate wrapped blob. Careful, we need to conditionally free
	 * rawBlob on error.
	 */
	CssmData encryptedBlob;
	CssmData remData;
	WrappedKey.KeyData.Data = NULL;		// ignore possible incoming KeyData
	WrappedKey.KeyData.Length = 0;
	
	try {
		if(isNullWrap) {
			/* copy raw blob to caller's wrappedKey */
			copyCssmData(rawBlob, 
				CssmData::overlay(WrappedKey.KeyData), 
				normAllocator);
			wrappedHdr.Format   = rawFormat; 
		}
		else {
			/* encrypt rawBlob using caller's context, then encode to
			 * WrappedKey.KeyData */
			CSSM_SIZE bytesEncrypted;
			EncryptData(CCHandle,
				Context,
				&rawBlob,			// ClearBufs[]
				1,					// ClearBufCount
				&encryptedBlob,		// CipherBufs[],
				1,					// CipherBufCount,
				bytesEncrypted,
				remData,
				Privilege);
	
			// I'm not 100% sure about this....
			assert(remData.Length == 0);
			encryptedBlob.Length = bytesEncrypted;
			WrappedKey.KeyData = encryptedBlob;
			wrappedHdr.BlobType = CSSM_KEYBLOB_WRAPPED;
			// OK to be zero or not present 
			wrappedHdr.WrapMode = Context.getInt(
				CSSM_ATTRIBUTE_MODE);
		}
	}
	catch (...) {
		errorLog0("WrapKey: EncryptData() threw exception\n");
		if(allocdRawBlob) {
			freeCssmData(rawBlob, privAllocator);
		}
		freeCssmData(remData,normAllocator);
		throw;
	}
	if(allocdRawBlob) {
		freeCssmData(rawBlob, privAllocator);
	}
	freeCssmData(remData, normAllocator);
}
/*
 * Unwrap key function. Used for:
 *
 * -- Given key of BlobType CSSM_KEYBLOB_WRAPPED, decode and decrypt
 *    it, yielding a key in either raw or reference format. Unwrapping
 *    key may be either raw or reference. The context must match
 *    the unwrapping key (ALGCLASS_SYMMETRIC  or ALGCLASS_ASYMMETRIC).
 *
 *	  Private keys are assumed to be PKCS8 encoded; session keys  
 *    are assumed to be PKCS7 encoded. 
 *
 * -- Convert a Raw key to a reference key (with no decrypting).
 *    This is called a NULL unwrap; no unwrapping key need be present in
 *    the context, but the context must be of class 
 *    ALGCLASS_SYMMETRIC and algorithm ALGID_NONE.
 */ 
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;				// CKT_Public, etc. 
	CSSM_KEYBLOB_FORMAT		wrapFormat = WrappedKey.blobFormat();
	
	/* obtain unwrapping key if present */
	unwrappingKey = Context.get<CssmKey>(CSSM_ATTRIBUTE_KEY);
	if(unwrappingKey == NULL) {
		if((Context.algorithm() == CSSM_ALGID_NONE) &&
		   (Context.type() == CSSM_ALGCLASS_SYMMETRIC)) {
				// NULL unwrap, OK
				isNullUnwrap = true;
		}
		else {
			errorLog0("UnwrapKey: missing wrapping key\n");
			CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_KEY);
		}
	}

	/* 
	 * validate unwrappingKey 
	 */
	if(!isNullUnwrap) {
		/* make sure unwrapping key type matches context */
		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);
		cspVerifyKeyTimes(unwrappingKey->KeyHeader);
	}

	/* validate WrappedKey */
	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	/* ALLOW_PUB_KEY_WRAP */
			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);
		}
	}

	/* validate requested storage and usage */
	cspKeyStorage keyStorage = cspParseKeyAttr(keyType, KeyAttr);
	switch(keyStorage) {
		case CKS_Ref:
		case CKS_Data:
			break;		// OK
		default:
			CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
	}
	cspValidateKeyUsageBits(keyType,  KeyUsage);

	/* prepare outgoing header */
	CssmKey::Header &unwrappedHdr = UnwrappedKey.header();
	const CssmKey::Header &wrappedHdr   = WrappedKey.header();
	setKeyHeader(unwrappedHdr,
		plugin.myGuid(),
		wrappedHdr.algorithm(),		// same as incoming 
		wrappedHdr.keyClass(),		// same as incoming
		KeyAttr & ~KEY_ATTR_RETURN_MASK,
		KeyUsage);
	unwrappedHdr.LogicalKeySizeInBits = wrappedHdr.LogicalKeySizeInBits;
	unwrappedHdr.StartDate = wrappedHdr.StartDate;
	unwrappedHdr.EndDate = wrappedHdr.EndDate;
	UnwrappedKey.KeyData.Data = NULL;	// ignore possible incoming KeyData
	UnwrappedKey.KeyData.Length = 0;
	
	/* validate wrappedKey format */
	if(!isNullUnwrap) {
		switch(wrapFormat) {
			case CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7:
				if(WrappedKey.keyClass() != CSSM_KEYCLASS_SESSION_KEY) {
					/* this unwrapping style only for symmetric keys */
					CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
				}
				break;
			case CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8:
			case CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSL:
				if(WrappedKey.keyClass() != CSSM_KEYCLASS_PRIVATE_KEY) {
					/* these unwrapping styles only for private keys */
					CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
				}
				break;
			case CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM:
				UnwrapKeyCms(CCHandle,
						Context,
						WrappedKey,
						CredAndAclEntry,
						UnwrappedKey,
						DescriptiveData,
						Privilege,
						keyStorage);
				return;
			case CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSH1:
				/* RSA private key, unwrap to ref key only */
				if(WrappedKey.keyClass() != CSSM_KEYCLASS_PRIVATE_KEY) {
					CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
				}
				if(WrappedKey.algorithm() != CSSM_ALGID_RSA) {
					CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
				}
				if(keyStorage != CKS_Ref) {
					errorLog0("UNwrapKey: OPENSSH1 only wraps to reference key\n");
					CssmError::throwMe(CSSMERR_CSP_KEY_BLOB_TYPE_INCORRECT);
				}
				UnwrapKeyOpenSSH1(CCHandle,
						Context,
						WrappedKey,
						CredAndAclEntry,
						UnwrappedKey,
						DescriptiveData,
						Privilege,
						keyStorage);
				return;
			default:
				CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_WRAPPED_KEY_FORMAT);
		}
	}

	/* Get key blob, decoding and decrypting if necessary */
	CssmData decodedBlob;
	CssmData remData;
	try {
		if(isNullUnwrap) {
			/* simple copy of raw blob */
			copyData(WrappedKey.KeyData, 
				UnwrappedKey.KeyData, 
				normAllocator);
			unwrappedHdr.BlobType = CSSM_KEYBLOB_RAW;
			unwrappedHdr.Format   = wrapFormat; 
		}
		else {
			decodedBlob = CssmData::overlay(WrappedKey.KeyData);
			CSSM_SIZE bytesDecrypted;		
			CssmData *unwrapData = 
				CssmData::overlay(&UnwrappedKey.KeyData);
				
			DecryptData(CCHandle,
				Context,
				&decodedBlob,		// CipherBufs[],
				1,					// CipherBufCount,
				unwrapData,			// ClearBufs[]
				1,					// ClearBufCount
				bytesDecrypted,
				remData,
				Privilege);
	
			// I'm not 100% sure about this....
			assert(remData.Length == 0);
			UnwrappedKey.KeyData.Length = bytesDecrypted;
			unwrappedHdr.BlobType = CSSM_KEYBLOB_RAW;
			
			/* 
			 * Figure out various header fields from resulting blob
			 */
			switch(wrapFormat) {
				case CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7:
					unwrappedHdr.Format = 
						CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING;
					if(unwrappedHdr.LogicalKeySizeInBits == 0) {
						unwrappedHdr.LogicalKeySizeInBits =
							(unsigned)(bytesDecrypted * 8);
					}
					/* app has to infer/know algorithm */
					break;
				case CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8:
					pkcs8InferKeyHeader(UnwrappedKey);
					break;
				case CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSL:
					/* 
					 * App told us key algorithm (in WrappedKey).
					 * Infer format and key size. 
					 */
					opensslInferKeyHeader(UnwrappedKey);
					break;
			}
		}
	}
	catch (...) {
		errorLog0("UnwrapKey: DecryptData() threw exception\n");
		freeCssmData(remData, normAllocator);
		throw;
	}
	freeCssmData(remData, normAllocator);

	/* 
	 * One more thing: cook up a BinaryKey if caller wants a 
	 * reference key.
	 */
	if(keyStorage == CKS_Ref) {
		/*
		 * We have a key in raw format; convert to BinaryKey.
		 */
		BinaryKey *binKey = NULL;
		CSPKeyInfoProvider *provider = infoProvider(UnwrappedKey);
		/* optional parameter-bearing key */
		CssmKey *paramKey = Context.get<CssmKey>(CSSM_ATTRIBUTE_PARAM_KEY);
		provider->CssmKeyToBinary(paramKey, UnwrappedKey.KeyHeader.KeyAttr, &binKey);
		addRefKey(*binKey, UnwrappedKey);
		delete provider;
	}
}
//
// Decode a key blob
//
void DatabaseCryptoCore::decodeKeyCore(KeyBlob *blob,
    CssmKey &key, void * &pubAcl, void * &privAcl) const
{    
    // Assemble the encrypted blob as a CSSM "wrapped key"
    CssmKey wrappedKey;
    wrappedKey.KeyHeader = blob->header;
	h2ni(wrappedKey.KeyHeader);
    wrappedKey.blobType(blob->wrappedHeader.blobType);
    wrappedKey.blobFormat(blob->wrappedHeader.blobFormat);
    wrappedKey.wrapAlgorithm(blob->wrappedHeader.wrapAlgorithm);
    wrappedKey.wrapMode(blob->wrappedHeader.wrapMode);
    wrappedKey.KeyData = CssmData(blob->cryptoBlob(), blob->cryptoBlobLength());
	
	bool inTheClear = blob->isClearText();
	if(!inTheClear) {
		// verify signature (check against corruption)
		assert(isValid());		// need our database secrets
		CssmData signChunk[] = {
			CssmData::wrap(blob, fieldOffsetOf(&KeyBlob::blobSignature)),
			CssmData(blob->publicAclBlob(), blob->publicAclBlobLength() + blob->cryptoBlobLength())
		};
		CSSM_ALGORITHMS verifyAlgorithm = CSSM_ALGID_SHA1HMAC;
	#if defined(COMPAT_OSX_10_0)
		if (blob->version() == blob->version_MacOS_10_0)
			verifyAlgorithm = CSSM_ALGID_SHA1HMAC_LEGACY;	// BSafe bug compatibility
	#endif
		VerifyMac verifier(Server::csp(), verifyAlgorithm);
		verifier.key(mSigningKey);
		CssmData signature(blob->blobSignature, sizeof(blob->blobSignature));
		verifier.verify(signChunk, 2, signature);
    }
	/* else signature indicates cleartext */
	
    // extract and hold some header bits the CSP does not want to see
    uint32 heldAttributes = n2h(blob->header.attributes()) & managedAttributes;
   
	CssmData privAclData;
	if(inTheClear) {
		/* NULL unwrap */
		UnwrapKey unwrap(Server::csp(), CSSM_ALGID_NONE);
		wrappedKey.clearAttribute(managedAttributes);    //@@@ shouldn't be needed(?)
		unwrap(wrappedKey,
			KeySpec(n2h(blob->header.usage()),
				(n2h(blob->header.attributes()) & ~managedAttributes) | forcedAttributes),
			key, &privAclData);
	}
	else {
		// decrypt the key using an unwrapping operation
		UnwrapKey unwrap(Server::csp(), CSSM_ALGID_3DES_3KEY_EDE);
		unwrap.key(mEncryptionKey);
		unwrap.mode(CSSM_ALGMODE_CBCPadIV8);
		unwrap.padding(CSSM_PADDING_PKCS1);
		CssmData ivd(blob->iv, sizeof(blob->iv)); unwrap.initVector(ivd);
		unwrap.add(CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT,
			uint32(CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM));
		wrappedKey.clearAttribute(managedAttributes);    //@@@ shouldn't be needed(?)
		unwrap(wrappedKey,
			KeySpec(n2h(blob->header.usage()),
				(n2h(blob->header.attributes()) & ~managedAttributes) | forcedAttributes),
			key, &privAclData);
    }
	
    // compare retrieved key headers with blob headers (sanity check)
    // @@@ this should probably be checked over carefully
    CssmKey::Header &real = key.header();
    CssmKey::Header &incoming = blob->header;
	n2hi(incoming);

    if (real.HeaderVersion != incoming.HeaderVersion ||
        real.cspGuid() != incoming.cspGuid())
        CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
    if (real.algorithm() != incoming.algorithm())
        CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
        
    // re-insert held bits
    key.header().KeyAttr |= heldAttributes;
    
	if(inTheClear && (real.keyClass() != CSSM_KEYCLASS_PUBLIC_KEY)) {
		/* Spoof - cleartext KeyBlob passed off as private key */
        CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
	}
	
    // got a valid key: return the pieces
    pubAcl = blob->publicAclBlob();		// points into blob (shared)
    privAcl = privAclData;				// was allocated by CSP decrypt, else NULL for
										// cleatext keys
    // key was set by unwrap operation
}
//
// Encode a key blob
//
KeyBlob *DatabaseCryptoCore::encodeKeyCore(const CssmKey &inKey,
    const CssmData &publicAcl, const CssmData &privateAcl,
	bool inTheClear) const
{
    CssmKey key = inKey;
	uint8 iv[8];
	CssmKey wrappedKey;

	if(inTheClear && (privateAcl.Length != 0)) {
		/* can't store private ACL component in the clear */
		CssmError::throwMe(CSSMERR_DL_INVALID_ACCESS_CREDENTIALS);
	}
	
    // extract and hold some header bits the CSP does not want to see
    uint32 heldAttributes = key.attributes() & managedAttributes;
    key.clearAttribute(managedAttributes);
	key.setAttribute(forcedAttributes);
    
	if(inTheClear) {
		/* NULL wrap of public key */
		WrapKey wrap(Server::csp(), CSSM_ALGID_NONE);
		wrap(key, wrappedKey, NULL);
	}
	else {
		assert(isValid());		// need our database secrets
		
		// create new IV
		Server::active().random(iv);
		
	   // use a CMS wrap to encrypt the key
		WrapKey wrap(Server::csp(), CSSM_ALGID_3DES_3KEY_EDE);
		wrap.key(mEncryptionKey);
		wrap.mode(CSSM_ALGMODE_CBCPadIV8);
		wrap.padding(CSSM_PADDING_PKCS1);
		CssmData ivd(iv, sizeof(iv)); wrap.initVector(ivd);
		wrap.add(CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT,
			uint32(CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM));
		wrap(key, wrappedKey, &privateAcl);
    }
	
    // stick the held attribute bits back in
	key.clearAttribute(forcedAttributes);
    key.setAttribute(heldAttributes);
    
    // allocate the final KeyBlob, uh, blob
    size_t length = sizeof(KeyBlob) + publicAcl.length() + wrappedKey.length();
    KeyBlob *blob = Allocator::standard().malloc<KeyBlob>(length);
    
    // assemble the KeyBlob
    memset(blob, 0, sizeof(KeyBlob));	// fill alignment gaps
    blob->initialize();
	if(!inTheClear) {
		memcpy(blob->iv, iv, sizeof(iv));
	}
    blob->header = key.header();
	h2ni(blob->header);	// endian-correct the header
    blob->wrappedHeader.blobType = wrappedKey.blobType();
    blob->wrappedHeader.blobFormat = wrappedKey.blobFormat();
    blob->wrappedHeader.wrapAlgorithm = wrappedKey.wrapAlgorithm();
    blob->wrappedHeader.wrapMode = wrappedKey.wrapMode();
    memcpy(blob->publicAclBlob(), publicAcl, publicAcl.length());
    blob->startCryptoBlob = sizeof(KeyBlob) + publicAcl.length();
    memcpy(blob->cryptoBlob(), wrappedKey.data(), wrappedKey.length());
    blob->totalLength = blob->startCryptoBlob + wrappedKey.length();
    
 	if(inTheClear) {
		/* indicate that this is cleartext for decoding */
		blob->setClearTextSignature();
	}
	else {
		// sign the blob
		CssmData signChunk[] = {
			CssmData(blob->data(), fieldOffsetOf(&KeyBlob::blobSignature)),
			CssmData(blob->publicAclBlob(), blob->publicAclBlobLength() + blob->cryptoBlobLength())
		};
		CssmData signature(blob->blobSignature, sizeof(blob->blobSignature));
		GenerateMac signer(Server::csp(), CSSM_ALGID_SHA1HMAC_LEGACY);	//@@@!!! CRUD
		signer.key(mSigningKey);
		signer.sign(signChunk, 2, signature);
		assert(signature.length() == sizeof(blob->blobSignature));
    }
	
    // all done. Clean up
    Server::csp()->allocator().free(wrappedKey);
    return blob;
}
void KeyDataAttributeCoder::decode(TokenContext *tokenContext,
	const MetaAttribute &metaAttribute, Record &record)
{
	const MetaRecord &mr = metaAttribute.metaRecord();
	CssmKey key;
	key.header().cspGuid(Guid::overlay(gGuidAppleSdCSPDL));
	key.blobType(CSSM_KEYBLOB_REFERENCE);
	key.blobFormat(CSSM_KEYBLOB_REF_FORMAT_INTEGER);
	key.algorithm(mr.metaAttribute(kSecKeyKeyType)
		.attribute(tokenContext, record).uint32Value());
	key.keyClass(mr.metaAttribute(kSecKeyKeyClass)
		.attribute(tokenContext, record).uint32Value());
	key.header().LogicalKeySizeInBits =
		mr.metaAttribute(kSecKeyKeySizeInBits).attribute(tokenContext, record)
			.uint32Value();

	key.header().KeyAttr =
		(mr.metaAttribute(kSecKeyPermanent).attribute(tokenContext, record)
			.boolValue() ? CSSM_KEYATTR_PERMANENT : 0)
		| (mr.metaAttribute(kSecKeyPrivate).attribute(tokenContext, record)
			.boolValue() ? CSSM_KEYATTR_PRIVATE : 0)
		| (mr.metaAttribute(kSecKeyModifiable).attribute(tokenContext, record)
			.boolValue() ? CSSM_KEYATTR_MODIFIABLE : 0)
		| (mr.metaAttribute(kSecKeySensitive).attribute(tokenContext, record)
			.boolValue() ? CSSM_KEYATTR_SENSITIVE : 0)
		| (mr.metaAttribute(kSecKeyAlwaysSensitive)
			.attribute(tokenContext, record)
				.boolValue() ? CSSM_KEYATTR_ALWAYS_SENSITIVE : 0)
		| (mr.metaAttribute(kSecKeyExtractable).attribute(tokenContext, record)
			.boolValue() ? CSSM_KEYATTR_EXTRACTABLE : 0)
		| (mr.metaAttribute(kSecKeyNeverExtractable)
			.attribute(tokenContext, record)
				.boolValue() ? CSSM_KEYATTR_NEVER_EXTRACTABLE : 0);

	CSSM_KEYUSE usage =
		(mr.metaAttribute(kSecKeyEncrypt).attribute(tokenContext, record)
			.boolValue() ? CSSM_KEYUSE_ENCRYPT : 0)
		| (mr.metaAttribute(kSecKeyDecrypt).attribute(tokenContext, record)
			.boolValue() ? CSSM_KEYUSE_DECRYPT : 0)
		| (mr.metaAttribute(kSecKeySign).attribute(tokenContext, record)
			.boolValue() ? CSSM_KEYUSE_SIGN : 0)
		| (mr.metaAttribute(kSecKeyVerify).attribute(tokenContext, record)
			.boolValue() ? CSSM_KEYUSE_VERIFY : 0)
		| (mr.metaAttribute(kSecKeySignRecover).attribute(tokenContext, record)
			.boolValue() ? CSSM_KEYUSE_SIGN_RECOVER : 0)
		| (mr.metaAttribute(kSecKeyVerifyRecover)
			.attribute(tokenContext, record)
				.boolValue() ? CSSM_KEYUSE_VERIFY_RECOVER : 0)
		| (mr.metaAttribute(kSecKeyWrap).attribute(tokenContext, record)
			.boolValue() ? CSSM_KEYUSE_WRAP : 0)
		| (mr.metaAttribute(kSecKeyUnwrap).attribute(tokenContext, record)
			.boolValue() ? CSSM_KEYUSE_UNWRAP : 0)
		| (mr.metaAttribute(kSecKeyDerive).attribute(tokenContext, record)
			.boolValue() ? CSSM_KEYUSE_DERIVE : 0);
	if (usage == (CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_SIGN
		| CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_SIGN_RECOVER
		| CSSM_KEYUSE_VERIFY_RECOVER | CSSM_KEYUSE_WRAP | CSSM_KEYUSE_UNWRAP
		| CSSM_KEYUSE_DERIVE))
		usage = CSSM_KEYUSE_ANY;

	key.header().KeyUsage = usage;

	// Dates
	mr.metaAttribute(kSecKeyStartDate).attribute(tokenContext, record)
		.getDateValue(key.header().StartDate);
	mr.metaAttribute(kSecKeyEndDate).attribute(tokenContext, record)
		.getDateValue(key.header().EndDate);

	record.attributeAtIndex(metaAttribute.attributeIndex(),
		new Attribute(&key, sizeof(key)));
}
Exemplo n.º 13
0
// Called from subclass after it allocates its BinaryKeys.
// Caller frees BinaryKeys if we throw any exception. 
void AppleKeyPairGenContext::generate(
	const Context 	&context, 
	AppleCSPSession	&session,
	CssmKey 		&pubKey, 
	BinaryKey 		*pubBinKey,
	CssmKey 		&privKey,
	BinaryKey		*privBinKey)
{
	uint32			keySize;
	cspKeyStorage 	privStorage;
	cspKeyStorage 	pubStorage;
	CssmKey::Header	&pubHdr  = pubKey.header(); 
	CssmKey::Header	&privHdr = privKey.header(); 
	
	// validate context and key header args
	pubStorage  = cspParseKeyAttr(CKT_Public,  pubHdr.KeyAttr);
	privStorage = cspParseKeyAttr(CKT_Private, privHdr.KeyAttr);
	cspValidateKeyUsageBits(CKT_Public,  pubHdr.KeyUsage);
	cspValidateKeyUsageBits(CKT_Private, privHdr.KeyUsage);
	
	// have subclass generate the key pairs in the form of 
	// its native BinaryKeys
	generate(context, *pubBinKey, *privBinKey, keySize);

	// FIXME - Any other header setup?
	pubHdr.LogicalKeySizeInBits = 
		privHdr.LogicalKeySizeInBits = keySize;
	pubHdr.KeyAttr  &= ~KEY_ATTR_RETURN_MASK;
	privHdr.KeyAttr &= ~KEY_ATTR_RETURN_MASK;
		 
	// Handle key formatting. Delete the BinaryKeys if
	// we're not creating ref keys, after safe completion of 
	// generateKeyBlob (which may throw, in which case the binary keys
	// get deleted by our caller). 
	CSSM_KEYATTR_FLAGS attrFlags = 0;
	switch(pubStorage) {
		case CKS_Ref:
			session.addRefKey(*pubBinKey, pubKey);
			break;
		case CKS_Data:
			pubHdr.Format = requestedKeyFormat(context, pubKey);
			pubBinKey->mKeyHeader  = pubHdr;
			pubBinKey->generateKeyBlob(
				session.normAlloc(),		// alloc in user space
				CssmData::overlay(pubKey.KeyData),
				pubHdr.Format,
				session,
				NULL,						// no paramKey here!
				attrFlags);
			break;
		case CKS_None:
			break;
	}
	switch(privStorage) {
		case CKS_Ref:
			session.addRefKey(*privBinKey, privKey);
			break;
		case CKS_Data:
			privHdr.Format = requestedKeyFormat(context, privKey);
			privBinKey->mKeyHeader = privHdr;
			privBinKey->generateKeyBlob(
				session.normAlloc(),		// alloc in user space
				CssmData::overlay(privKey.KeyData),
				privHdr.Format,
				session,
				NULL,
				attrFlags);
			break;
		case CKS_None:
			break;
	}
	if(pubStorage != CKS_Ref) {
		delete pubBinKey;
	}
	if(privStorage != CKS_Ref) {
		delete privBinKey;
	}
}
Exemplo n.º 14
0
/*
 * Called from subclass's generate method. Subclass is also a 
 * AppleCSPContext.
 */
void AppleSymmKeyGenContext::generateSymKey(
	const Context 	&context, 
	AppleCSPSession	&session,		// for ref keys
	CssmKey 		&cssmKey)		// RETURNED 
{
	/* there really is no legal way this should throw... */
	uint32 reqKeySize = context.getInt(
		CSSM_ATTRIBUTE_KEY_LENGTH, 
		CSSMERR_CSP_MISSING_ATTR_KEY_LENGTH);
	if((reqKeySize < minSizeInBits) ||
	   (reqKeySize > maxSizeInBits)) {
		CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEY_SIZE);
	}
	if(mustBeByteSized) {
		if((reqKeySize & 0x7) != 0) {
			CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEY_SIZE);
		}
	}
	
	// validate KeyAtrr and KeyUsage already present in header
	cspKeyStorage 	keyStorage;
	CssmKey::Header	&hdr  = cssmKey.header(); 
	
	keyStorage = cspParseKeyAttr(CKT_Session,  hdr.KeyAttr);
	cspValidateKeyUsageBits(CKT_Session, hdr.KeyUsage);
	hdr.KeyAttr  &= ~KEY_ATTR_RETURN_MASK;
	
	hdr.LogicalKeySizeInBits = reqKeySize;
	uint32 keySizeInBytes = (reqKeySize + 7) / 8;
	SymmetricBinaryKey *binKey = NULL;
	CssmData *keyData = NULL;
	
	switch(keyStorage) {
		case CKS_None:
			/* no way */
			CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
		case CKS_Ref:
			/* cook up a symmetric binary key */
			binKey = new SymmetricBinaryKey(reqKeySize);
			keyData = &binKey->mKeyData;
			break;
		case CKS_Data:
			/* key bytes --> caller's cssmKey */
			keyData = &(CssmData::overlay(cssmKey.KeyData));
			setUpCssmData(*keyData, keySizeInBytes, 
				session.normAlloc());
			break;
	}
	
	// in any case, fill key bytes with random data
	session.getRandomBytes(keySizeInBytes, keyData->Data);

	if(keyStorage == CKS_Ref) {
		session.addRefKey(*binKey, cssmKey);
	}
	else {
		/* Raw data */
		hdr.BlobType = CSSM_KEYBLOB_RAW;
		hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING; 
	}

	// FIXME - any other header fields?
}