2  * Copyright (c) 2000-2001,2011-2012,2014 Apple Inc. All Rights Reserved. 
   4  * The contents of this file constitute Original Code as defined in and are 
   5  * subject to the Apple Public Source License Version 1.2 (the 'License'). 
   6  * You may not use this file except in compliance with the License. Please obtain 
   7  * a copy of the License at http://www.apple.com/publicsource and read it before 
  10  * This Original Code and all software distributed under the License are 
  11  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS 
  12  * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT 
  13  * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 
  14  * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the 
  15  * specific language governing rights and limitations under the License. 
  20 // SSCSPSession.cpp - Security Server CSP session. 
  22 #include "SSCSPSession.h" 
  24 #include "CSPDLPlugin.h" 
  25 #include "SSDatabase.h" 
  26 #include "SSDLSession.h" 
  28 #include <security_cdsa_utilities/cssmbridge.h> 
  32 using namespace SecurityServer
; 
  35 // SSCSPSession -- Security Server CSP session 
  37 SSCSPSession::SSCSPSession(CSSM_MODULE_HANDLE handle
, 
  39                                                    const CSSM_VERSION 
&version
, 
  41                                                    CSSM_SERVICE_TYPE subserviceType
, 
  42                                                    CSSM_ATTACH_FLAGS attachFlags
, 
  43                                                    const CSSM_UPCALLS 
&upcalls
, 
  44                                                    SSCSPDLSession 
&ssCSPDLSession
, 
  45                                                    CssmClient::CSP 
&rawCsp
) 
  46 : CSPFullPluginSession(handle
, plug
, version
, subserviceId
, subserviceType
, 
  47                                            attachFlags
, upcalls
), 
  48   mSSCSPDLSession(ssCSPDLSession
), 
  49   mSSFactory(plug
.mSSFactory
), 
  51   mClientSession(Allocator::standard(), *this) 
  53         mClientSession
.registerForAclEdits(SSCSPDLSession::didChangeKeyAclCallback
, &mSSCSPDLSession
); 
  57 // Called at (CSSM) context create time. This is ignored; we do a full  
  58 // context setup later, at setupContext time.  
  60 CSPFullPluginSession::CSPContext 
* 
  61 SSCSPSession::contextCreate(CSSM_CC_HANDLE handle
, const Context 
&context
) 
  68 // Called by CSPFullPluginSession when an op is actually commencing. 
  69 // Context can safely assumed to be fully formed and stable for the 
  70 // duration of the  op; thus we wait until now to set up our  
  71 // CSPContext as appropriate to the op. 
  74 SSCSPSession::setupContext(CSPContext 
* &cspCtx
, 
  75                                                    const Context 
&context
, 
  78         // note we skip this if this CSPContext is being reused 
  82                 if (mSSFactory
.setup(*this, cspCtx
, context
, encoding
)) 
  86                 if (mBSafe4Factory
.setup(*this, cspCtx
, context
)) 
  89                 if (mCryptKitFactory
.setup(*this, cspCtx
, context
)) 
  93         CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM
); 
 102 SSCSPSession::getDatabase(const Context 
&context
) 
 104         return getDatabase(context
.get
<CSSM_DL_DB_HANDLE
>(CSSM_ATTRIBUTE_DL_DB_HANDLE
)); 
 108 SSCSPSession::getDatabase(CSSM_DL_DB_HANDLE 
*aDLDbHandle
) 
 111                 return findSession
<SSDLSession
>(aDLDbHandle
->DLHandle
).findDbHandle(aDLDbHandle
->DBHandle
); 
 118 // Reference Key management 
 121 SSCSPSession::makeReferenceKey(KeyHandle inKeyHandle
, CssmKey 
&ioKey
, SSDatabase 
&inSSDatabase
, 
 122                                                            uint32 inKeyAttr
, const CssmData 
*inKeyLabel
) 
 124         return mSSCSPDLSession
.makeReferenceKey(*this, inKeyHandle
, ioKey
, inSSDatabase
, inKeyAttr
, inKeyLabel
); 
 128 SSCSPSession::lookupKey(const CssmKey 
&inKey
) 
 130         return mSSCSPDLSession
.lookupKey(inKey
); 
 135 // Key creating and handeling members 
 138 SSCSPSession::WrapKey(CSSM_CC_HANDLE CCHandle
, 
 139                                           const Context 
&context
, 
 140                                           const AccessCredentials 
&AccessCred
, 
 142                                           const CssmData 
*DescriptiveData
, 
 144                                           CSSM_PRIVILEGE Privilege
) 
 146         // @@@ Deal with permanent keys 
 147         const CssmKey 
*keyInContext 
= 
 148                 context
.get
<const CssmKey
>(CSSM_ATTRIBUTE_KEY
); 
 150         KeyHandle contextKeyHandle 
= (keyInContext
 
 151                                                                   ? lookupKey(*keyInContext
).keyHandle() 
 153         clientSession().wrapKey(context
, contextKeyHandle
, 
 154                                                         lookupKey(Key
).keyHandle(), &AccessCred
, 
 155                                                         DescriptiveData
, WrappedKey
, *this); 
 159 SSCSPSession::UnwrapKey(CSSM_CC_HANDLE CCHandle
, 
 160                                                 const Context 
&context
, 
 161                                                 const CssmKey 
*PublicKey
, 
 162                                                 const CssmWrappedKey 
&WrappedKey
, 
 165                                                 const CssmData 
*KeyLabel
, 
 166                                                 const CSSM_RESOURCE_CONTROL_CONTEXT 
*CredAndAclEntry
, 
 167                                                 CssmKey 
&UnwrappedKey
, 
 168                                                 CssmData 
&DescriptiveData
, 
 169                                                 CSSM_PRIVILEGE Privilege
) 
 171         SSDatabase database 
= getDatabase(context
); 
 172         validateKeyAttr(KeyAttr
); 
 173         const AccessCredentials 
*cred 
= NULL
; 
 174         const AclEntryInput 
*owner 
= NULL
; 
 177                 cred 
= AccessCredentials::overlay(CredAndAclEntry
->AccessCred
); 
 178                 owner 
= &AclEntryInput::overlay(CredAndAclEntry
->InitialAclEntry
); 
 181         KeyHandle publicKey 
= noKey
; 
 184                 if (PublicKey
->blobType() == CSSM_KEYBLOB_RAW
) 
 186                         // @@@ We need to unwrap the publicKey into the SecurityServer 
 188                         CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
); 
 191                         publicKey 
= lookupKey(*PublicKey
).keyHandle(); 
 194         // @@@ Deal with permanent keys 
 195         const CssmKey 
*keyInContext 
= 
 196                 context
.get
<const CssmKey
>(CSSM_ATTRIBUTE_KEY
); 
 198         KeyHandle contextKeyHandle 
= 
 199                 keyInContext 
? lookupKey(*keyInContext
).keyHandle() : noKey
; 
 201         KeyHandle unwrappedKeyHandle
; 
 202         clientSession().unwrapKey(database
.dbHandle(), context
, contextKeyHandle
, 
 203                                                           publicKey
, WrappedKey
, KeyUsage
, KeyAttr
, 
 204                                                           cred
, owner
, DescriptiveData
, unwrappedKeyHandle
, 
 205                                                           UnwrappedKey
.header(), *this);         
 206         makeReferenceKey(unwrappedKeyHandle
, UnwrappedKey
, database
, KeyAttr
, 
 211 SSCSPSession::DeriveKey(CSSM_CC_HANDLE ccHandle
, 
 212                                                 const Context 
&context
, 
 216                                                 const CssmData 
*keyLabel
, 
 217                                                 const CSSM_RESOURCE_CONTROL_CONTEXT 
*credAndAclEntry
, 
 220         SSDatabase database 
= getDatabase(context
); 
 221         validateKeyAttr(keyAttr
); 
 222         const AccessCredentials 
*cred 
= NULL
; 
 223         const AclEntryInput 
*owner 
= NULL
; 
 226                 cred 
= AccessCredentials::overlay(credAndAclEntry
->AccessCred
); 
 227                 owner 
= &AclEntryInput::overlay(credAndAclEntry
->InitialAclEntry
); 
 230         /* optional BaseKey */ 
 231         const CssmKey 
*keyInContext 
= 
 232                 context
.get
<const CssmKey
>(CSSM_ATTRIBUTE_KEY
); 
 233         KeyHandle contextKeyHandle 
= 
 234                 keyInContext 
? lookupKey(*keyInContext
).keyHandle() : noKey
; 
 236         switch(context
.algorithm()) { 
 237         case CSSM_ALGID_KEYCHAIN_KEY
: 
 239                         // special interpretation: take DLDBHandle -> DbHandle from params 
 240                         clientSession().extractMasterKey(database
.dbHandle(), context
, 
 241                                 getDatabase(param
.interpretedAs
<CSSM_DL_DB_HANDLE
>(CSSMERR_CSP_INVALID_ATTR_DL_DB_HANDLE
)).dbHandle(), 
 242                                 keyUsage
, keyAttr
, cred
, owner
, keyHandle
, derivedKey
.header()); 
 246                 clientSession().deriveKey(database
.dbHandle(), context
, contextKeyHandle
, keyUsage
, 
 247                                         keyAttr
, param
, cred
, owner
, keyHandle
, derivedKey
.header()); 
 250         makeReferenceKey(keyHandle
, derivedKey
, database
, keyAttr
, keyLabel
); 
 254 SSCSPSession::GenerateKey(CSSM_CC_HANDLE ccHandle
, 
 255                                                   const Context 
&context
, 
 258                                                   const CssmData 
*keyLabel
, 
 259                                                   const CSSM_RESOURCE_CONTROL_CONTEXT 
*credAndAclEntry
, 
 261                                                   CSSM_PRIVILEGE privilege
) 
 263         SSDatabase database 
= getDatabase(context
); 
 264         validateKeyAttr(keyAttr
); 
 265         const AccessCredentials 
*cred 
= NULL
; 
 266         const AclEntryInput 
*owner 
= NULL
; 
 269                 cred 
= AccessCredentials::overlay(credAndAclEntry
->AccessCred
); 
 270                 owner 
= &AclEntryInput::overlay(credAndAclEntry
->InitialAclEntry
); 
 274         clientSession().generateKey(database
.dbHandle(), context
, keyUsage
, 
 275                                                                 keyAttr
, cred
, owner
, keyHandle
, key
.header()); 
 276         makeReferenceKey(keyHandle
, key
, database
, keyAttr
, keyLabel
); 
 280 SSCSPSession::GenerateKeyPair(CSSM_CC_HANDLE ccHandle
, 
 281                                                           const Context 
&context
, 
 282                                                           uint32 publicKeyUsage
, 
 283                                                           uint32 publicKeyAttr
, 
 284                                                           const CssmData 
*publicKeyLabel
, 
 286                                                           uint32 privateKeyUsage
, 
 287                                                           uint32 privateKeyAttr
, 
 288                                                           const CssmData 
*privateKeyLabel
, 
 289                                                           const CSSM_RESOURCE_CONTROL_CONTEXT 
*credAndAclEntry
, 
 291                                                           CSSM_PRIVILEGE privilege
) 
 293         SSDatabase database 
= getDatabase(context
); 
 294         validateKeyAttr(publicKeyAttr
); 
 295         validateKeyAttr(privateKeyAttr
); 
 296         const AccessCredentials 
*cred 
= NULL
; 
 297         const AclEntryInput 
*owner 
= NULL
; 
 300                 cred 
= AccessCredentials::overlay(credAndAclEntry
->AccessCred
); 
 301                 owner 
= &AclEntryInput::overlay(credAndAclEntry
->InitialAclEntry
); 
 305          * Public keys must be extractable in the clear - that's the Apple 
 306          * policy. The raw CSP is unable to enforce the extractable 
 307          * bit since it always sees that as true (it's managed and forced 
 308          * true by the SecurityServer). So... 
 310         if(!(publicKeyAttr 
& CSSM_KEYATTR_EXTRACTABLE
)) { 
 311                         CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK
); 
 313         KeyHandle pubKeyHandle
, privKeyHandle
; 
 314         clientSession().generateKey(database
.dbHandle(), context
, 
 315                                                            publicKeyUsage
, publicKeyAttr
, 
 316                                                            privateKeyUsage
, privateKeyAttr
, 
 318                                                            pubKeyHandle
, publicKey
.header(), 
 319                                                            privKeyHandle
, privateKey
.header()); 
 320         makeReferenceKey(privKeyHandle
, privateKey
, database
, privateKeyAttr
, 
 322         // @@@ What if this throws, we need to free privateKey. 
 323         makeReferenceKey(pubKeyHandle
, publicKey
, database
, publicKeyAttr
, 
 328 SSCSPSession::ObtainPrivateKeyFromPublicKey(const CssmKey 
&PublicKey
, 
 335 SSCSPSession::QueryKeySizeInBits(CSSM_CC_HANDLE CCHandle
, 
 336                                                                  const Context 
*Context
, 
 338                                                                  CSSM_KEY_SIZE 
&KeySize
) 
 344 SSCSPSession::FreeKey(const AccessCredentials 
*accessCred
, 
 345                                           CssmKey 
&ioKey
, CSSM_BOOL deleteKey
) 
 347         if (ioKey
.blobType() == CSSM_KEYBLOB_REFERENCE
) 
 349         StLock
<Mutex
> _(mSSCSPDLSession
.mKeyDeletionMutex
); 
 350                 // @@@ Note that this means that detaching a session should free 
 351                 // all keys ascociated with it or else... 
 355                 // @@@ There are thread safety issues when deleting a key that is 
 356                 // in use by another thread, but the answer to that is: Don't do 
 359                 // Find the key in the map.  Tell tell the key to free itself 
 360                 // (when the auto_ptr deletes the key it removes itself from the map).  
 361             secinfo("freeKey", "CSPDL FreeKey"); 
 362                 auto_ptr
<SSKey
> ssKey(&mSSCSPDLSession
.find
<SSKey
>(ioKey
)); 
 363                 ssKey
->free(accessCred
, ioKey
, deleteKey
); 
 367                 CSPFullPluginSession::FreeKey(accessCred
, ioKey
, deleteKey
); 
 376 SSCSPSession::GenerateRandom(CSSM_CC_HANDLE ccHandle
, 
 377                                                          const Context 
&context
, 
 378                                                          CssmData 
&randomNumber
) 
 380     checkOperation(context
.type(), CSSM_ALGCLASS_RANDOMGEN
); 
 381         // if (context.algorithm() != @@@) CssmError::throwMe(ALGORITHM_NOT_SUPPORTED); 
 382         uint32 needed 
= context
.getInt(CSSM_ATTRIBUTE_OUTPUT_SIZE
, CSSMERR_CSP_MISSING_ATTR_OUTPUT_SIZE
); 
 384         // @@@ What about the seed? 
 385     if (randomNumber
.length()) 
 387         if (randomNumber
.length() < needed
) 
 388             CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR
); 
 389                 clientSession().generateRandom(context
, randomNumber
); 
 393         randomNumber
.Data 
= alloc
<uint8
>(needed
); 
 396                         clientSession().generateRandom(context
, randomNumber
); 
 400                         free(randomNumber
.Data
); 
 401                         randomNumber
.Data 
= NULL
; 
 408 // Login/Logout and token operational maintainance.  These mean little 
 409 // without support by the actual implementation, but we can help... 
 410 // @@@ Should this be in CSP[non-Full]PluginSession? 
 413 SSCSPSession::Login(const AccessCredentials 
&AccessCred
, 
 414                                         const CssmData 
*LoginName
, 
 415                                         const void *Reserved
) 
 417         // @@@ Do a login to the securityServer making keys persistent until it 
 423 SSCSPSession::Logout() 
 429 SSCSPSession::VerifyDevice(const CssmData 
&DeviceCert
) 
 431         CssmError::throwMe(CSSMERR_CSP_DEVICE_VERIFY_FAILED
); 
 435 SSCSPSession::GetOperationalStatistics(CSPOperationalStatistics 
&statistics
) 
 442 // Utterly miscellaneous, rarely used, strange functions 
 445 SSCSPSession::RetrieveCounter(CssmData 
&Counter
) 
 451 SSCSPSession::RetrieveUniqueId(CssmData 
&UniqueID
) 
 457 SSCSPSession::GetTimeValue(CSSM_ALGORITHMS TimeAlgorithm
, CssmData 
&TimeData
) 
 464 // ACL retrieval and change operations 
 467 SSCSPSession::GetKeyOwner(const CssmKey 
&Key
, 
 468                                                   CSSM_ACL_OWNER_PROTOTYPE 
&Owner
) 
 470         lookupKey(Key
).getOwner(Owner
, *this); 
 474 SSCSPSession::ChangeKeyOwner(const AccessCredentials 
&AccessCred
, 
 476                                                          const CSSM_ACL_OWNER_PROTOTYPE 
&NewOwner
) 
 478         lookupKey(Key
).changeOwner(AccessCred
, 
 479                                                            AclOwnerPrototype::overlay(NewOwner
)); 
 483 SSCSPSession::GetKeyAcl(const CssmKey 
&Key
, 
 484                                                 const CSSM_STRING 
*SelectionTag
, 
 485                                                 uint32 
&NumberOfAclInfos
, 
 486                                                 CSSM_ACL_ENTRY_INFO_PTR 
&AclInfos
) 
 488         lookupKey(Key
).getAcl(reinterpret_cast<const char *>(SelectionTag
), 
 490                                                   reinterpret_cast<AclEntryInfo 
*&>(AclInfos
), *this); 
 494 SSCSPSession::ChangeKeyAcl(const AccessCredentials 
&AccessCred
, 
 495                                                    const CSSM_ACL_EDIT 
&AclEdit
, 
 498         lookupKey(Key
).changeAcl(AccessCred
, AclEdit::overlay(AclEdit
)); 
 502 SSCSPSession::GetLoginOwner(CSSM_ACL_OWNER_PROTOTYPE 
&Owner
) 
 508 SSCSPSession::ChangeLoginOwner(const AccessCredentials 
&AccessCred
, 
 509                                                            const CSSM_ACL_OWNER_PROTOTYPE 
&NewOwner
) 
 515 SSCSPSession::GetLoginAcl(const CSSM_STRING 
*SelectionTag
, 
 516                                                   uint32 
&NumberOfAclInfos
, 
 517                                                   CSSM_ACL_ENTRY_INFO_PTR 
&AclInfos
) 
 523 SSCSPSession::ChangeLoginAcl(const AccessCredentials 
&AccessCred
, 
 524                                                          const CSSM_ACL_EDIT 
&AclEdit
) 
 535 SSCSPSession::PassThrough(CSSM_CC_HANDLE CCHandle
, 
 536                                                   const Context 
&context
, 
 537                                                   uint32 passThroughId
, 
 541     checkOperation(context
.type(), CSSM_ALGCLASS_NONE
); 
 542         switch (passThroughId
) { 
 543         case CSSM_APPLESCPDL_CSP_GET_KEYHANDLE
: 
 545                 // inData unused, must be NULL 
 547                         CssmError::throwMe(CSSM_ERRCODE_INVALID_INPUT_POINTER
); 
 549                 // outData required, must be pointer-to-pointer-to-KeyHandle 
 550                 KeyHandle 
&result 
= Required(reinterpret_cast<KeyHandle 
*>(outData
)); 
 552                 // we'll take the key from the context 
 554                         context
.get
<const CssmKey
>(CSSM_ATTRIBUTE_KEY
,  CSSMERR_CSP_MISSING_ATTR_KEY
); 
 557                 result 
= lookupKey(key
).keyHandle(); 
 560         case CSSM_APPLECSP_KEYDIGEST
: 
 562                 // inData unused, must be NULL 
 564                         CssmError::throwMe(CSSM_ERRCODE_INVALID_INPUT_POINTER
); 
 569                 // take the key from the context, convert to KeyHandle 
 571                         context
.get
<const CssmKey
>(CSSM_ATTRIBUTE_KEY
,  CSSMERR_CSP_MISSING_ATTR_KEY
);  
 572                 KeyHandle keyHandle 
= lookupKey(key
).keyHandle(); 
 574                 // allocate digest holder on app's behalf 
 575                 CSSM_DATA 
*digest 
= alloc
<CSSM_DATA
>(sizeof(CSSM_DATA
)); 
 581                         clientSession().getKeyDigest(keyHandle
, CssmData::overlay(*digest
)); 
 592                 CssmError::throwMe(CSSM_ERRCODE_INVALID_PASSTHROUGH_ID
); 
 596 /* Validate requested key attr flags for newly generated keys */ 
 597 void SSCSPSession::validateKeyAttr(uint32 reqKeyAttr
) 
 599         if(reqKeyAttr 
& (CSSM_KEYATTR_RETURN_DATA
)) { 
 600                 /* CSPDL only supports reference keys */ 
 601                 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYATTR_MASK
); 
 603         if(reqKeyAttr 
& (CSSM_KEYATTR_ALWAYS_SENSITIVE 
|  
 604                                      CSSM_KEYATTR_NEVER_EXTRACTABLE
)) { 
 605                 /* invalid for any CSP */ 
 606                 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK
); 
 608         /* There may be more, but we'll leave it to SS and CSP to decide */