2  * Copyright (c) 2004,2008,2011-2012 Apple Inc. All Rights Reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   6  * This file contains Original Code and/or Modifications of Original Code 
   7  * as defined in and that are subject to the Apple Public Source License 
   8  * Version 2.0 (the 'License'). You may not use this file except in 
   9  * compliance with the License. Please obtain a copy of the License at 
  10  * http://www.opensource.apple.com/apsl/ and read it before using this 
  13  * The Original Code and all software distributed under the License are 
  14  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  15  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  16  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  17  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  18  * Please see the License for the specific language governing rights and 
  19  * limitations under the License. 
  21  * @APPLE_LICENSE_HEADER_END@ 
  26 // SDCSPSession.cpp - Security Server CSP session. 
  28 #include "SDCSPSession.h" 
  30 #include "SDCSPDLPlugin.h" 
  31 #include "SDDLSession.h" 
  33 #include <security_cdsa_utilities/cssmbridge.h> 
  37 using namespace SecurityServer
; 
  40 // SDCSPSession -- Security Server CSP session 
  42 SDCSPSession::SDCSPSession(CSSM_MODULE_HANDLE handle
, 
  44                                                    const CSSM_VERSION 
&version
, 
  46                                                    CSSM_SERVICE_TYPE subserviceType
, 
  47                                                    CSSM_ATTACH_FLAGS attachFlags
, 
  48                                                    const CSSM_UPCALLS 
&upcalls
, 
  49                                                    SDCSPDLSession 
&ssCSPDLSession
, 
  50                                                    CssmClient::CSP 
&rawCsp
) 
  51 : CSPFullPluginSession(handle
, plug
, version
, subserviceId
, subserviceType
, 
  52                                            attachFlags
, upcalls
), 
  53   mSDCSPDLSession(ssCSPDLSession
), 
  54   mSDFactory(plug
.mSDFactory
), 
  56   mClientSession(Allocator::standard(), *this) 
  61 // Called at (CSSM) context create time. This is ignored; we do a full  
  62 // context setup later, at setupContext time.  
  64 CSPFullPluginSession::CSPContext 
* 
  65 SDCSPSession::contextCreate(CSSM_CC_HANDLE handle
, const Context 
&context
) 
  72 // Called by CSPFullPluginSession when an op is actually commencing. 
  73 // Context can safely assumed to be fully formed and stable for the 
  74 // duration of the  op; thus we wait until now to set up our  
  75 // CSPContext as appropriate to the op. 
  78 SDCSPSession::setupContext(CSPContext 
* &cspCtx
, 
  79                                                    const Context 
&context
, 
  82         // note we skip this if this CSPContext is being reused 
  86                 if (mSDFactory
.setup(*this, cspCtx
, context
, encoding
)) 
  90                 if (mBSafe4Factory
.setup(*this, cspCtx
, context
)) 
  93                 if (mCryptKitFactory
.setup(*this, cspCtx
, context
)) 
  97         CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM
); 
 106 SDCSPSession::getDatabase(const Context 
&context
) 
 108         return getDatabase(context
.get
<CSSM_DL_DB_HANDLE
>(CSSM_ATTRIBUTE_DL_DB_HANDLE
)); 
 112 SDCSPSession::getDatabase(CSSM_DL_DB_HANDLE 
*aDLDbHandle
) 
 115                 return aDLDbHandle
->DBHandle
; 
 117                 return CSSM_INVALID_HANDLE
; 
 122 // Reference Key management 
 125 SDCSPSession::makeReferenceKey(KeyHandle inKeyHandle
, CssmKey 
&ioKey
, CSSM_DB_HANDLE inDBHandle
, 
 126                                                            uint32 inKeyAttr
, const CssmData 
*inKeyLabel
) 
 128         return mSDCSPDLSession
.makeReferenceKey(*this, inKeyHandle
, ioKey
, inDBHandle
, inKeyAttr
, inKeyLabel
); 
 132 SDCSPSession::lookupKey(const CssmKey 
&inKey
) 
 134         return mSDCSPDLSession
.lookupKey(inKey
); 
 139 // Key creating and handeling members 
 142 SDCSPSession::WrapKey(CSSM_CC_HANDLE CCHandle
, 
 143                                           const Context 
&context
, 
 144                                           const AccessCredentials 
&AccessCred
, 
 146                                           const CssmData 
*DescriptiveData
, 
 148                                           CSSM_PRIVILEGE Privilege
) 
 150         // @@@ Deal with permanent keys 
 151         const CssmKey 
*keyInContext 
= 
 152                 context
.get
<const CssmKey
>(CSSM_ATTRIBUTE_KEY
); 
 154         KeyHandle contextKeyHandle 
= (keyInContext
 
 155                                                                   ? lookupKey(*keyInContext
).keyHandle() 
 157         clientSession().wrapKey(context
, contextKeyHandle
, 
 158                                                         lookupKey(Key
).keyHandle(), &AccessCred
, 
 159                                                         DescriptiveData
, WrappedKey
, *this); 
 163 SDCSPSession::UnwrapKey(CSSM_CC_HANDLE CCHandle
, 
 164                                                 const Context 
&context
, 
 165                                                 const CssmKey 
*PublicKey
, 
 166                                                 const CssmWrappedKey 
&WrappedKey
, 
 169                                                 const CssmData 
*KeyLabel
, 
 170                                                 const CSSM_RESOURCE_CONTROL_CONTEXT 
*CredAndAclEntry
, 
 171                                                 CssmKey 
&UnwrappedKey
, 
 172                                                 CssmData 
&DescriptiveData
, 
 173                                                 CSSM_PRIVILEGE Privilege
) 
 175         CSSM_DB_HANDLE database 
= getDatabase(context
); 
 176         validateKeyAttr(KeyAttr
); 
 177         const AccessCredentials 
*cred 
= NULL
; 
 178         const AclEntryInput 
*owner 
= NULL
; 
 181                 cred 
= AccessCredentials::overlay(CredAndAclEntry
->AccessCred
); 
 182                 owner 
= &AclEntryInput::overlay(CredAndAclEntry
->InitialAclEntry
); 
 185         KeyHandle publicKey 
= noKey
; 
 188                 if (PublicKey
->blobType() == CSSM_KEYBLOB_RAW
) 
 190                         // @@@ We need to unwrap the publicKey into the SecurityServer 
 192                         CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
); 
 195                         publicKey 
= lookupKey(*PublicKey
).keyHandle(); 
 198         // @@@ Deal with permanent keys 
 199         const CssmKey 
*keyInContext 
= 
 200                 context
.get
<const CssmKey
>(CSSM_ATTRIBUTE_KEY
); 
 202         KeyHandle contextKeyHandle 
= 
 203                 keyInContext 
? lookupKey(*keyInContext
).keyHandle() : noKey
; 
 205         KeyHandle unwrappedKeyHandle
; 
 206         clientSession().unwrapKey(ClientSession::toIPCHandle(database
), context
, contextKeyHandle
, 
 207                                                           publicKey
, WrappedKey
, KeyUsage
, KeyAttr
, 
 208                                                           cred
, owner
, DescriptiveData
, unwrappedKeyHandle
, 
 209                                                           UnwrappedKey
.header(), *this);         
 210         makeReferenceKey(unwrappedKeyHandle
, UnwrappedKey
, database
, KeyAttr
, 
 215 SDCSPSession::DeriveKey(CSSM_CC_HANDLE ccHandle
, 
 216                                                 const Context 
&context
, 
 220                                                 const CssmData 
*keyLabel
, 
 221                                                 const CSSM_RESOURCE_CONTROL_CONTEXT 
*credAndAclEntry
, 
 224         CSSM_DB_HANDLE database 
= getDatabase(context
); 
 225         validateKeyAttr(keyAttr
); 
 226         const AccessCredentials 
*cred 
= NULL
; 
 227         const AclEntryInput 
*owner 
= NULL
; 
 230                 cred 
= AccessCredentials::overlay(credAndAclEntry
->AccessCred
); 
 231                 owner 
= &AclEntryInput::overlay(credAndAclEntry
->InitialAclEntry
); 
 234         /* optional BaseKey */ 
 235         const CssmKey 
*keyInContext 
= 
 236                 context
.get
<const CssmKey
>(CSSM_ATTRIBUTE_KEY
); 
 237         KeyHandle contextKeyHandle 
= 
 238                 keyInContext 
? lookupKey(*keyInContext
).keyHandle() : noKey
; 
 240         switch(context
.algorithm()) { 
 241         case CSSM_ALGID_KEYCHAIN_KEY
: 
 243                         // special interpretation: take DLDBHandle -> DbHandle from params 
 244                         clientSession().extractMasterKey(ClientSession::toIPCHandle(database
), context
, 
 245                                 (DbHandle
)getDatabase(param
.interpretedAs
<CSSM_DL_DB_HANDLE
>(CSSMERR_CSP_INVALID_ATTR_DL_DB_HANDLE
)), 
 246                                 keyUsage
, keyAttr
, cred
, owner
, keyHandle
, derivedKey
.header()); 
 250             clientSession().deriveKey(ClientSession::toIPCHandle(database
), context
, contextKeyHandle
, keyUsage
, 
 251                                         keyAttr
, param
, cred
, owner
, keyHandle
, derivedKey
.header()); 
 254         makeReferenceKey(keyHandle
, derivedKey
, database
, keyAttr
, keyLabel
); 
 258 SDCSPSession::GenerateKey(CSSM_CC_HANDLE ccHandle
, 
 259                                                   const Context 
&context
, 
 262                                                   const CssmData 
*keyLabel
, 
 263                                                   const CSSM_RESOURCE_CONTROL_CONTEXT 
*credAndAclEntry
, 
 265                                                   CSSM_PRIVILEGE privilege
) 
 267         CSSM_DB_HANDLE database 
= getDatabase(context
); 
 268         validateKeyAttr(keyAttr
); 
 269         const AccessCredentials 
*cred 
= NULL
; 
 270         const AclEntryInput 
*owner 
= NULL
; 
 273                 cred 
= AccessCredentials::overlay(credAndAclEntry
->AccessCred
); 
 274                 owner 
= &AclEntryInput::overlay(credAndAclEntry
->InitialAclEntry
); 
 278         clientSession().generateKey(ClientSession::toIPCHandle(database
), context
, keyUsage
, 
 279                                                                 keyAttr
, cred
, owner
, keyHandle
, key
.header()); 
 280         makeReferenceKey(keyHandle
, key
, database
, keyAttr
, keyLabel
); 
 284 SDCSPSession::GenerateKeyPair(CSSM_CC_HANDLE ccHandle
, 
 285                                                           const Context 
&context
, 
 286                                                           uint32 publicKeyUsage
, 
 287                                                           uint32 publicKeyAttr
, 
 288                                                           const CssmData 
*publicKeyLabel
, 
 290                                                           uint32 privateKeyUsage
, 
 291                                                           uint32 privateKeyAttr
, 
 292                                                           const CssmData 
*privateKeyLabel
, 
 293                                                           const CSSM_RESOURCE_CONTROL_CONTEXT 
*credAndAclEntry
, 
 295                                                           CSSM_PRIVILEGE privilege
) 
 297         CSSM_DB_HANDLE database 
= getDatabase(context
); 
 298         validateKeyAttr(publicKeyAttr
); 
 299         validateKeyAttr(privateKeyAttr
); 
 300         const AccessCredentials 
*cred 
= NULL
; 
 301         const AclEntryInput 
*owner 
= NULL
; 
 304                 cred 
= AccessCredentials::overlay(credAndAclEntry
->AccessCred
); 
 305                 owner 
= &AclEntryInput::overlay(credAndAclEntry
->InitialAclEntry
); 
 309          * Public keys must be extractable in the clear - that's the Apple 
 310          * policy. The raw CSP is unable to enforce the extractable 
 311          * bit since it always sees that as true (it's managed and forced 
 312          * true by the SecurityServer). So... 
 314         if(!(publicKeyAttr 
& CSSM_KEYATTR_EXTRACTABLE
)) { 
 315                         CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK
); 
 317         KeyHandle pubKeyHandle
, privKeyHandle
; 
 318         clientSession().generateKey(ClientSession::toIPCHandle(database
), context
, 
 319                                                            publicKeyUsage
, publicKeyAttr
, 
 320                                                            privateKeyUsage
, privateKeyAttr
, 
 322                                                            pubKeyHandle
, publicKey
.header(), 
 323                                                            privKeyHandle
, privateKey
.header()); 
 324         makeReferenceKey(privKeyHandle
, privateKey
, database
, privateKeyAttr
, 
 326         // @@@ What if this throws, we need to free privateKey. 
 327         makeReferenceKey(pubKeyHandle
, publicKey
, database
, publicKeyAttr
, 
 332 SDCSPSession::ObtainPrivateKeyFromPublicKey(const CssmKey 
&PublicKey
, 
 339 SDCSPSession::QueryKeySizeInBits(CSSM_CC_HANDLE CCHandle
, 
 340                                                                  const Context 
*Context
, 
 342                                                                  CSSM_KEY_SIZE 
&KeySize
) 
 348 SDCSPSession::FreeKey(const AccessCredentials 
*accessCred
, 
 349                                           CssmKey 
&ioKey
, CSSM_BOOL deleteKey
) 
 351         if (ioKey
.blobType() == CSSM_KEYBLOB_REFERENCE
) 
 353                 // @@@ Note that this means that detaching a session should free 
 354                 // all keys ascociated with it or else... 
 358                 // @@@ There are thread safety issues when deleting a key that is 
 359                 // in use by another thread, but the answer to that is: Don't do 
 362                 // Find the key in the map.  Tell tell the key to free itself 
 363                 // (when the auto_ptr deletes the key it removes itself from the map).  
 364             secinfo("freeKey", "CSPDL FreeKey"); 
 365                 auto_ptr
<SDKey
> ssKey(&mSDCSPDLSession
.find
<SDKey
>(ioKey
)); 
 366                 ssKey
->free(accessCred
, ioKey
, deleteKey
); 
 370                 CSPFullPluginSession::FreeKey(accessCred
, ioKey
, deleteKey
); 
 379 SDCSPSession::GenerateRandom(CSSM_CC_HANDLE ccHandle
, 
 380                                                          const Context 
&context
, 
 381                                                          CssmData 
&randomNumber
) 
 383     checkOperation(context
.type(), CSSM_ALGCLASS_RANDOMGEN
); 
 384         // if (context.algorithm() != @@@) CssmError::throwMe(ALGORITHM_NOT_SUPPORTED); 
 385         uint32 needed 
= context
.getInt(CSSM_ATTRIBUTE_OUTPUT_SIZE
, CSSMERR_CSP_MISSING_ATTR_OUTPUT_SIZE
); 
 387         // @@@ What about the seed? 
 388     if (randomNumber
.length()) 
 390         if (randomNumber
.length() < needed
) 
 391             CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR
); 
 392                 clientSession().generateRandom(context
, randomNumber
); 
 396         randomNumber
.Data 
= alloc
<uint8
>(needed
); 
 399                         clientSession().generateRandom(context
, randomNumber
); 
 403                         free(randomNumber
.Data
); 
 404                         randomNumber
.Data 
= NULL
; 
 411 // Login/Logout and token operational maintainance.  These mean little 
 412 // without support by the actual implementation, but we can help... 
 413 // @@@ Should this be in CSP[non-Full]PluginSession? 
 416 SDCSPSession::Login(const AccessCredentials 
&AccessCred
, 
 417                                         const CssmData 
*LoginName
, 
 418                                         const void *Reserved
) 
 420         // @@@ Do a login to the securityServer making keys persistent until it 
 426 SDCSPSession::Logout() 
 432 SDCSPSession::VerifyDevice(const CssmData 
&DeviceCert
) 
 434         CssmError::throwMe(CSSMERR_CSP_DEVICE_VERIFY_FAILED
); 
 438 SDCSPSession::GetOperationalStatistics(CSPOperationalStatistics 
&statistics
) 
 445 // Utterly miscellaneous, rarely used, strange functions 
 448 SDCSPSession::RetrieveCounter(CssmData 
&Counter
) 
 454 SDCSPSession::RetrieveUniqueId(CssmData 
&UniqueID
) 
 460 SDCSPSession::GetTimeValue(CSSM_ALGORITHMS TimeAlgorithm
, CssmData 
&TimeData
) 
 467 // ACL retrieval and change operations 
 470 SDCSPSession::GetKeyOwner(const CssmKey 
&Key
, 
 471                                                   CSSM_ACL_OWNER_PROTOTYPE 
&Owner
) 
 473         lookupKey(Key
).getOwner(Owner
, *this); 
 477 SDCSPSession::ChangeKeyOwner(const AccessCredentials 
&AccessCred
, 
 479                                                          const CSSM_ACL_OWNER_PROTOTYPE 
&NewOwner
) 
 481         lookupKey(Key
).changeOwner(AccessCred
, 
 482                                                            AclOwnerPrototype::overlay(NewOwner
)); 
 486 SDCSPSession::GetKeyAcl(const CssmKey 
&Key
, 
 487                                                 const CSSM_STRING 
*SelectionTag
, 
 488                                                 uint32 
&NumberOfAclInfos
, 
 489                                                 CSSM_ACL_ENTRY_INFO_PTR 
&AclInfos
) 
 491         lookupKey(Key
).getAcl(reinterpret_cast<const char *>(SelectionTag
), 
 493                                                   reinterpret_cast<AclEntryInfo 
*&>(AclInfos
), *this); 
 497 SDCSPSession::ChangeKeyAcl(const AccessCredentials 
&AccessCred
, 
 498                                                    const CSSM_ACL_EDIT 
&AclEdit
, 
 501         lookupKey(Key
).changeAcl(AccessCred
, AclEdit::overlay(AclEdit
)); 
 505 SDCSPSession::GetLoginOwner(CSSM_ACL_OWNER_PROTOTYPE 
&Owner
) 
 511 SDCSPSession::ChangeLoginOwner(const AccessCredentials 
&AccessCred
, 
 512                                                            const CSSM_ACL_OWNER_PROTOTYPE 
&NewOwner
) 
 518 SDCSPSession::GetLoginAcl(const CSSM_STRING 
*SelectionTag
, 
 519                                                   uint32 
&NumberOfAclInfos
, 
 520                                                   CSSM_ACL_ENTRY_INFO_PTR 
&AclInfos
) 
 526 SDCSPSession::ChangeLoginAcl(const AccessCredentials 
&AccessCred
, 
 527                                                          const CSSM_ACL_EDIT 
&AclEdit
) 
 538 SDCSPSession::PassThrough(CSSM_CC_HANDLE CCHandle
, 
 539                                                   const Context 
&context
, 
 540                                                   uint32 passThroughId
, 
 544     checkOperation(context
.type(), CSSM_ALGCLASS_NONE
); 
 545         switch (passThroughId
) { 
 546         case CSSM_APPLESCPDL_CSP_GET_KEYHANDLE
: 
 548                 // inData unused, must be NULL 
 550                         CssmError::throwMe(CSSM_ERRCODE_INVALID_INPUT_POINTER
); 
 552                 // outData required, must be pointer-to-pointer-to-KeyHandle 
 553                 KeyHandle 
&result 
= Required(reinterpret_cast<KeyHandle 
*>(outData
)); 
 555                 // we'll take the key from the context 
 557                         context
.get
<const CssmKey
>(CSSM_ATTRIBUTE_KEY
,  CSSMERR_CSP_MISSING_ATTR_KEY
); 
 560                 result 
= lookupKey(key
).keyHandle(); 
 563         case CSSM_APPLECSP_KEYDIGEST
: 
 565                 // inData unused, must be NULL 
 567                         CssmError::throwMe(CSSM_ERRCODE_INVALID_INPUT_POINTER
); 
 572                 // take the key from the context, convert to KeyHandle 
 574                         context
.get
<const CssmKey
>(CSSM_ATTRIBUTE_KEY
,  CSSMERR_CSP_MISSING_ATTR_KEY
);  
 575                 KeyHandle keyHandle 
= lookupKey(key
).keyHandle(); 
 577                 // allocate digest holder on app's behalf 
 578                 CSSM_DATA 
*digest 
= alloc
<CSSM_DATA
>(sizeof(CSSM_DATA
)); 
 584                         clientSession().getKeyDigest(keyHandle
, CssmData::overlay(*digest
)); 
 595                 CssmError::throwMe(CSSM_ERRCODE_INVALID_PASSTHROUGH_ID
); 
 599 /* Validate requested key attr flags for newly generated keys */ 
 600 void SDCSPSession::validateKeyAttr(uint32 reqKeyAttr
) 
 602         if(reqKeyAttr 
& (CSSM_KEYATTR_RETURN_DATA
)) { 
 603                 /* CSPDL only supports reference keys */ 
 604                 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYATTR_MASK
); 
 606         if(reqKeyAttr 
& (CSSM_KEYATTR_ALWAYS_SENSITIVE 
|  
 607                                      CSSM_KEYATTR_NEVER_EXTRACTABLE
)) { 
 608                 /* invalid for any CSP */ 
 609                 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK
); 
 611         /* There may be more, but we'll leave it to SS and CSP to decide */