/* * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved. * * The contents of this file constitute Original Code as defined in and are * subject to the Apple Public Source License Version 1.2 (the 'License'). * You may not use this file except in compliance with the License. Please obtain * a copy of the License at http://www.apple.com/publicsource and read it before * using this file. * * This Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the * specific language governing rights and limitations under the License. */ // // SSCSPSession.cpp - Security Server CSP session. // #include "SSCSPSession.h" #include "CSPDLPlugin.h" #include "SSDatabase.h" #include "SSDLSession.h" #include "SSKey.h" #include using namespace std; using namespace SecurityServer; // // SSCSPSession -- Security Server CSP session // SSCSPSession::SSCSPSession(CSSM_MODULE_HANDLE handle, CSPDLPlugin &plug, const CSSM_VERSION &version, uint32 subserviceId, CSSM_SERVICE_TYPE subserviceType, CSSM_ATTACH_FLAGS attachFlags, const CSSM_UPCALLS &upcalls, SSCSPDLSession &ssCSPDLSession, CssmClient::CSP &rawCsp) : CSPFullPluginSession(handle, plug, version, subserviceId, subserviceType, attachFlags, upcalls), mSSCSPDLSession(ssCSPDLSession), mSSFactory(plug.mSSFactory), mRawCsp(rawCsp), mClientSession(CssmAllocator::standard(), *this) { } // // Called at (CSSM) context create time. This is ignored; we do a full // context setup later, at setupContext time. // CSPFullPluginSession::CSPContext * SSCSPSession::contextCreate(CSSM_CC_HANDLE handle, const Context &context) { return NULL; } // // Called by CSPFullPluginSession when an op is actually commencing. // Context can safely assumed to be fully formed and stable for the // duration of the op; thus we wait until now to set up our // CSPContext as appropriate to the op. // void SSCSPSession::setupContext(CSPContext * &cspCtx, const Context &context, bool encoding) { // note we skip this if this CSPContext is being reused if (cspCtx == NULL) { if (mSSFactory.setup(*this, cspCtx, context, encoding)) return; #if 0 if (mBSafe4Factory.setup(*this, cspCtx, context)) return; if (mCryptKitFactory.setup(*this, cspCtx, context)) return; #endif CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM); } } // // DL interaction // SSDatabase SSCSPSession::getDatabase(const Context &context) { CSSM_DL_DB_HANDLE *aDLDbHandle = context.get(CSSM_ATTRIBUTE_DL_DB_HANDLE); if (!aDLDbHandle) return SSDatabase(); return findSession(aDLDbHandle->DLHandle).findDbHandle(aDLDbHandle->DBHandle); } // // Reference Key management // void SSCSPSession::makeReferenceKey(KeyHandle inKeyHandle, CssmKey &ioKey, SSDatabase &inSSDatabase, uint32 inKeyAttr, const CssmData *inKeyLabel) { return mSSCSPDLSession.makeReferenceKey(*this, inKeyHandle, ioKey, inSSDatabase, inKeyAttr, inKeyLabel); } SSKey & SSCSPSession::lookupKey(const CssmKey &inKey) { return mSSCSPDLSession.lookupKey(inKey); } // // Key creating and handeling members // void SSCSPSession::WrapKey(CSSM_CC_HANDLE CCHandle, const Context &context, const AccessCredentials &AccessCred, const CssmKey &Key, const CssmData *DescriptiveData, CssmKey &WrappedKey, CSSM_PRIVILEGE Privilege) { // @@@ Deal with permanent keys const CssmKey *keyInContext = context.get(CSSM_ATTRIBUTE_KEY); KeyHandle contextKeyHandle = (keyInContext ? lookupKey(*keyInContext).keyHandle() : noKey); clientSession().wrapKey(context, contextKeyHandle, lookupKey(Key).keyHandle(), &AccessCred, DescriptiveData, WrappedKey, *this); } void SSCSPSession::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) { SSDatabase 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(CSSM_ATTRIBUTE_KEY); KeyHandle contextKeyHandle = keyInContext ? lookupKey(*keyInContext).keyHandle() : noKey; KeyHandle unwrappedKeyHandle; clientSession().unwrapKey(database.dbHandle(), context, contextKeyHandle, publicKey, WrappedKey, KeyUsage, KeyAttr, cred, owner, DescriptiveData, unwrappedKeyHandle, UnwrappedKey.header(), *this); makeReferenceKey(unwrappedKeyHandle, UnwrappedKey, database, KeyAttr, KeyLabel); } void SSCSPSession::DeriveKey(CSSM_CC_HANDLE ccHandle, const Context &context, CssmData ¶m, uint32 keyUsage, uint32 keyAttr, const CssmData *keyLabel, const CSSM_RESOURCE_CONTROL_CONTEXT *credAndAclEntry, CssmKey &derivedKey) { SSDatabase 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(CSSM_ATTRIBUTE_KEY); KeyHandle contextKeyHandle = keyInContext ? lookupKey(*keyInContext).keyHandle() : noKey; KeyHandle keyHandle; clientSession().deriveKey(database.dbHandle(), context, contextKeyHandle, keyUsage, keyAttr, param, cred, owner, keyHandle, derivedKey.header()); makeReferenceKey(keyHandle, derivedKey, database, keyAttr, keyLabel); } void SSCSPSession::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) { SSDatabase 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(database.dbHandle(), context, keyUsage, keyAttr, cred, owner, keyHandle, key.header()); makeReferenceKey(keyHandle, key, database, keyAttr, keyLabel); } void SSCSPSession::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) { SSDatabase 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); } KeyHandle pubKeyHandle, privKeyHandle; clientSession().generateKey(database.dbHandle(), 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 SSCSPSession::ObtainPrivateKeyFromPublicKey(const CssmKey &PublicKey, CssmKey &PrivateKey) { unimplemented(); } void SSCSPSession::QueryKeySizeInBits(CSSM_CC_HANDLE CCHandle, const Context &Context, const CssmKey &Key, CSSM_KEY_SIZE &KeySize) { unimplemented(); } void SSCSPSession::FreeKey(const AccessCredentials *accessCred, CssmKey &ioKey, CSSM_BOOL deleteKey) { if (ioKey.blobType() == CSSM_KEYBLOB_REFERENCE) { // @@@ Note that this means that detaching a session should free // all keys ascociated with it or else... // -- or else what? // exactly! // @@@ There are thread safety issues when deleting a key that is // in use by another thread, but the answer to that is: Don't do // that! // Find the key in the map. Tell tell the key to free itself // (when the auto_ptr deletes the key it removes itself from the map). auto_ptr ssKey(&mSSCSPDLSession.find(ioKey)); ssKey->free(accessCred, ioKey, deleteKey); } else { CSPFullPluginSession::FreeKey(accessCred, ioKey, deleteKey); } } // // Generation stuff. // void SSCSPSession::GenerateRandom(CSSM_CC_HANDLE ccHandle, const Context &context, CssmData &randomNumber) { checkOperation(context.type(), CSSM_ALGCLASS_RANDOMGEN); // if (context.algorithm() != @@@) CssmError::throwMe(ALGORITHM_NOT_SUPPORTED); uint32 needed = context.getInt(CSSM_ATTRIBUTE_OUTPUT_SIZE, CSSMERR_CSP_MISSING_ATTR_OUTPUT_SIZE); // @@@ What about the seed? if (randomNumber.length()) { if (randomNumber.length() < needed) CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR); randomNumber.Length = needed; clientSession().generateRandom(randomNumber); } else { randomNumber.Data = alloc(needed); try { randomNumber.Length = needed; clientSession().generateRandom(randomNumber); } catch(...) { free(randomNumber.Data); randomNumber.Data = NULL; throw; } } } // // Login/Logout and token operational maintainance. These mean little // without support by the actual implementation, but we can help... // @@@ Should this be in CSP[non-Full]PluginSession? // void SSCSPSession::Login(const AccessCredentials &AccessCred, const CssmData *LoginName, const void *Reserved) { // @@@ Do a login to the securityServer making keys persistant until it // goes away unimplemented(); } void SSCSPSession::Logout() { unimplemented(); } void SSCSPSession::VerifyDevice(const CssmData &DeviceCert) { CssmError::throwMe(CSSMERR_CSP_DEVICE_VERIFY_FAILED); } void SSCSPSession::GetOperationalStatistics(CSPOperationalStatistics &statistics) { unimplemented(); } // // Utterly miscellaneous, rarely used, strange functions // void SSCSPSession::RetrieveCounter(CssmData &Counter) { unimplemented(); } void SSCSPSession::RetrieveUniqueId(CssmData &UniqueID) { unimplemented(); } void SSCSPSession::GetTimeValue(CSSM_ALGORITHMS TimeAlgorithm, CssmData &TimeData) { unimplemented(); } // // ACL retrieval and change operations // void SSCSPSession::GetKeyOwner(const CssmKey &Key, CSSM_ACL_OWNER_PROTOTYPE &Owner) { lookupKey(Key).getOwner(Owner, *this); } void SSCSPSession::ChangeKeyOwner(const AccessCredentials &AccessCred, const CssmKey &Key, const CSSM_ACL_OWNER_PROTOTYPE &NewOwner) { lookupKey(Key).changeOwner(AccessCred, AclOwnerPrototype::overlay(NewOwner)); } void SSCSPSession::GetKeyAcl(const CssmKey &Key, const CSSM_STRING *SelectionTag, uint32 &NumberOfAclInfos, CSSM_ACL_ENTRY_INFO_PTR &AclInfos) { lookupKey(Key).getAcl(reinterpret_cast(SelectionTag), NumberOfAclInfos, reinterpret_cast(AclInfos), *this); } void SSCSPSession::ChangeKeyAcl(const AccessCredentials &AccessCred, const CSSM_ACL_EDIT &AclEdit, const CssmKey &Key) { lookupKey(Key).changeAcl(AccessCred, AclEdit::overlay(AclEdit)); } void SSCSPSession::GetLoginOwner(CSSM_ACL_OWNER_PROTOTYPE &Owner) { unimplemented(); } void SSCSPSession::ChangeLoginOwner(const AccessCredentials &AccessCred, const CSSM_ACL_OWNER_PROTOTYPE &NewOwner) { unimplemented(); } void SSCSPSession::GetLoginAcl(const CSSM_STRING *SelectionTag, uint32 &NumberOfAclInfos, CSSM_ACL_ENTRY_INFO_PTR &AclInfos) { unimplemented(); } void SSCSPSession::ChangeLoginAcl(const AccessCredentials &AccessCred, const CSSM_ACL_EDIT &AclEdit) { unimplemented(); } // // Passthroughs (by default, unimplemented) // void SSCSPSession::PassThrough(CSSM_CC_HANDLE CCHandle, const Context &Context, uint32 PassThroughId, const void *InData, void **OutData) { unimplemented(); } /* Validate requested key attr flags for newly generated keys */ void SSCSPSession::validateKeyAttr(uint32 reqKeyAttr) { if(reqKeyAttr & (CSSM_KEYATTR_RETURN_DATA)) { /* CSPDL only supports reference keys */ CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYATTR_MASK); } if(reqKeyAttr & (CSSM_KEYATTR_ALWAYS_SENSITIVE | CSSM_KEYATTR_NEVER_EXTRACTABLE)) { /* invalid for any CSP */ CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK); } /* There may be more, but we'll leave it to SS and CSP to decide */ }