2  * Copyright (c) 2000-2001 Apple Computer, 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" 
  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(CssmAllocator::standard(), *this) 
  56 // Called at (CSSM) context create time. This is ignored; we do a full  
  57 // context setup later, at setupContext time.  
  59 CSPFullPluginSession::CSPContext 
* 
  60 SSCSPSession::contextCreate(CSSM_CC_HANDLE handle
, const Context 
&context
) 
  67 // Called by CSPFullPluginSession when an op is actually commencing. 
  68 // Context can safely assumed to be fully formed and stable for the 
  69 // duration of the  op; thus we wait until now to set up our  
  70 // CSPContext as appropriate to the op. 
  73 SSCSPSession::setupContext(CSPContext 
* &cspCtx
, 
  74                                                    const Context 
&context
, 
  77         // note we skip this if this CSPContext is being reused 
  81                 if (mSSFactory
.setup(*this, cspCtx
, context
, encoding
)) 
  85                 if (mBSafe4Factory
.setup(*this, cspCtx
, context
)) 
  88                 if (mCryptKitFactory
.setup(*this, cspCtx
, context
)) 
  92         CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM
); 
 101 SSCSPSession::getDatabase(const Context 
&context
) 
 103         return getDatabase(context
.get
<CSSM_DL_DB_HANDLE
>(CSSM_ATTRIBUTE_DL_DB_HANDLE
)); 
 107 SSCSPSession::getDatabase(CSSM_DL_DB_HANDLE 
*aDLDbHandle
) 
 110                 return findSession
<SSDLSession
>(aDLDbHandle
->DLHandle
).findDbHandle(aDLDbHandle
->DBHandle
); 
 117 // Reference Key management 
 120 SSCSPSession::makeReferenceKey(KeyHandle inKeyHandle
, CssmKey 
&ioKey
, SSDatabase 
&inSSDatabase
, 
 121                                                            uint32 inKeyAttr
, const CssmData 
*inKeyLabel
) 
 123         return mSSCSPDLSession
.makeReferenceKey(*this, inKeyHandle
, ioKey
, inSSDatabase
, inKeyAttr
, inKeyLabel
); 
 127 SSCSPSession::lookupKey(const CssmKey 
&inKey
) 
 129         return mSSCSPDLSession
.lookupKey(inKey
); 
 134 // Key creating and handeling members 
 137 SSCSPSession::WrapKey(CSSM_CC_HANDLE CCHandle
, 
 138                                           const Context 
&context
, 
 139                                           const AccessCredentials 
&AccessCred
, 
 141                                           const CssmData 
*DescriptiveData
, 
 143                                           CSSM_PRIVILEGE Privilege
) 
 145         // @@@ Deal with permanent keys 
 146         const CssmKey 
*keyInContext 
= 
 147                 context
.get
<const CssmKey
>(CSSM_ATTRIBUTE_KEY
); 
 149         KeyHandle contextKeyHandle 
= (keyInContext
 
 150                                                                   ? lookupKey(*keyInContext
).keyHandle() 
 152         clientSession().wrapKey(context
, contextKeyHandle
, 
 153                                                         lookupKey(Key
).keyHandle(), &AccessCred
, 
 154                                                         DescriptiveData
, WrappedKey
, *this); 
 158 SSCSPSession::UnwrapKey(CSSM_CC_HANDLE CCHandle
, 
 159                                                 const Context 
&context
, 
 160                                                 const CssmKey 
*PublicKey
, 
 161                                                 const CssmWrappedKey 
&WrappedKey
, 
 164                                                 const CssmData 
*KeyLabel
, 
 165                                                 const CSSM_RESOURCE_CONTROL_CONTEXT 
*CredAndAclEntry
, 
 166                                                 CssmKey 
&UnwrappedKey
, 
 167                                                 CssmData 
&DescriptiveData
, 
 168                                                 CSSM_PRIVILEGE Privilege
) 
 170         SSDatabase database 
= getDatabase(context
); 
 171         validateKeyAttr(KeyAttr
); 
 172         const AccessCredentials 
*cred 
= NULL
; 
 173         const AclEntryInput 
*owner 
= NULL
; 
 176                 cred 
= AccessCredentials::overlay(CredAndAclEntry
->AccessCred
); 
 177                 owner 
= &AclEntryInput::overlay(CredAndAclEntry
->InitialAclEntry
); 
 180         KeyHandle publicKey 
= noKey
; 
 183                 if (PublicKey
->blobType() == CSSM_KEYBLOB_RAW
) 
 185                         // @@@ We need to unwrap the publicKey into the SecurityServer 
 187                         CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
); 
 190                         publicKey 
= lookupKey(*PublicKey
).keyHandle(); 
 193         // @@@ Deal with permanent keys 
 194         const CssmKey 
*keyInContext 
= 
 195                 context
.get
<const CssmKey
>(CSSM_ATTRIBUTE_KEY
); 
 197         KeyHandle contextKeyHandle 
= 
 198                 keyInContext 
? lookupKey(*keyInContext
).keyHandle() : noKey
; 
 200         KeyHandle unwrappedKeyHandle
; 
 201         clientSession().unwrapKey(database
.dbHandle(), context
, contextKeyHandle
, 
 202                                                           publicKey
, WrappedKey
, KeyUsage
, KeyAttr
, 
 203                                                           cred
, owner
, DescriptiveData
, unwrappedKeyHandle
, 
 204                                                           UnwrappedKey
.header(), *this);         
 205         makeReferenceKey(unwrappedKeyHandle
, UnwrappedKey
, database
, KeyAttr
, 
 210 SSCSPSession::DeriveKey(CSSM_CC_HANDLE ccHandle
, 
 211                                                 const Context 
&context
, 
 215                                                 const CssmData 
*keyLabel
, 
 216                                                 const CSSM_RESOURCE_CONTROL_CONTEXT 
*credAndAclEntry
, 
 219         SSDatabase database 
= getDatabase(context
); 
 220         validateKeyAttr(keyAttr
); 
 221         const AccessCredentials 
*cred 
= NULL
; 
 222         const AclEntryInput 
*owner 
= NULL
; 
 225                 cred 
= AccessCredentials::overlay(credAndAclEntry
->AccessCred
); 
 226                 owner 
= &AclEntryInput::overlay(credAndAclEntry
->InitialAclEntry
); 
 229         /* optional BaseKey */ 
 230         const CssmKey 
*keyInContext 
= 
 231                 context
.get
<const CssmKey
>(CSSM_ATTRIBUTE_KEY
); 
 232         KeyHandle contextKeyHandle 
= 
 233                 keyInContext 
? lookupKey(*keyInContext
).keyHandle() : noKey
; 
 235         switch(context
.algorithm()) { 
 236         case CSSM_ALGID_KEYCHAIN_KEY
: 
 238                         // special interpretation: take DLDBHandle -> DbHandle from params 
 239                         clientSession().extractMasterKey(database
.dbHandle(), context
, 
 240                                 getDatabase(param
.interpretedAs
<CSSM_DL_DB_HANDLE
>(CSSMERR_CSP_INVALID_ATTR_DL_DB_HANDLE
)).dbHandle(), 
 241                                 keyUsage
, keyAttr
, cred
, owner
, keyHandle
, derivedKey
.header()); 
 245                 clientSession().deriveKey(database
.dbHandle(), context
, contextKeyHandle
, keyUsage
, 
 246                                         keyAttr
, param
, cred
, owner
, keyHandle
, derivedKey
.header()); 
 249         makeReferenceKey(keyHandle
, derivedKey
, database
, keyAttr
, keyLabel
); 
 253 SSCSPSession::GenerateKey(CSSM_CC_HANDLE ccHandle
, 
 254                                                   const Context 
&context
, 
 257                                                   const CssmData 
*keyLabel
, 
 258                                                   const CSSM_RESOURCE_CONTROL_CONTEXT 
*credAndAclEntry
, 
 260                                                   CSSM_PRIVILEGE privilege
) 
 262         SSDatabase database 
= getDatabase(context
); 
 263         validateKeyAttr(keyAttr
); 
 264         const AccessCredentials 
*cred 
= NULL
; 
 265         const AclEntryInput 
*owner 
= NULL
; 
 268                 cred 
= AccessCredentials::overlay(credAndAclEntry
->AccessCred
); 
 269                 owner 
= &AclEntryInput::overlay(credAndAclEntry
->InitialAclEntry
); 
 273         clientSession().generateKey(database
.dbHandle(), context
, keyUsage
, 
 274                                                                 keyAttr
, cred
, owner
, keyHandle
, key
.header()); 
 275         makeReferenceKey(keyHandle
, key
, database
, keyAttr
, keyLabel
); 
 279 SSCSPSession::GenerateKeyPair(CSSM_CC_HANDLE ccHandle
, 
 280                                                           const Context 
&context
, 
 281                                                           uint32 publicKeyUsage
, 
 282                                                           uint32 publicKeyAttr
, 
 283                                                           const CssmData 
*publicKeyLabel
, 
 285                                                           uint32 privateKeyUsage
, 
 286                                                           uint32 privateKeyAttr
, 
 287                                                           const CssmData 
*privateKeyLabel
, 
 288                                                           const CSSM_RESOURCE_CONTROL_CONTEXT 
*credAndAclEntry
, 
 290                                                           CSSM_PRIVILEGE privilege
) 
 292         SSDatabase database 
= getDatabase(context
); 
 293         validateKeyAttr(publicKeyAttr
); 
 294         validateKeyAttr(privateKeyAttr
); 
 295         const AccessCredentials 
*cred 
= NULL
; 
 296         const AclEntryInput 
*owner 
= NULL
; 
 299                 cred 
= AccessCredentials::overlay(credAndAclEntry
->AccessCred
); 
 300                 owner 
= &AclEntryInput::overlay(credAndAclEntry
->InitialAclEntry
); 
 304          * Public keys must be extractable in the clear - that's the Apple 
 305          * policy. The raw CSP is unable to enforce the extractable 
 306          * bit since it always sees that as true (it's managed and forced 
 307          * true by the SecurityServer). So... 
 309         if(!(publicKeyAttr 
& CSSM_KEYATTR_EXTRACTABLE
)) { 
 310                         CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK
); 
 312         KeyHandle pubKeyHandle
, privKeyHandle
; 
 313         clientSession().generateKey(database
.dbHandle(), context
, 
 314                                                            publicKeyUsage
, publicKeyAttr
, 
 315                                                            privateKeyUsage
, privateKeyAttr
, 
 317                                                            pubKeyHandle
, publicKey
.header(), 
 318                                                            privKeyHandle
, privateKey
.header()); 
 319         makeReferenceKey(privKeyHandle
, privateKey
, database
, privateKeyAttr
, 
 321         // @@@ What if this throws, we need to free privateKey. 
 322         makeReferenceKey(pubKeyHandle
, publicKey
, database
, publicKeyAttr
, 
 327 SSCSPSession::ObtainPrivateKeyFromPublicKey(const CssmKey 
&PublicKey
, 
 334 SSCSPSession::QueryKeySizeInBits(CSSM_CC_HANDLE CCHandle
, 
 335                                                                  const Context 
&Context
, 
 337                                                                  CSSM_KEY_SIZE 
&KeySize
) 
 343 SSCSPSession::FreeKey(const AccessCredentials 
*accessCred
, 
 344                                           CssmKey 
&ioKey
, CSSM_BOOL deleteKey
) 
 346         if (ioKey
.blobType() == CSSM_KEYBLOB_REFERENCE
) 
 348                 // @@@ Note that this means that detaching a session should free 
 349                 // all keys ascociated with it or else... 
 353                 // @@@ There are thread safety issues when deleting a key that is 
 354                 // in use by another thread, but the answer to that is: Don't do 
 357                 // Find the key in the map.  Tell tell the key to free itself 
 358                 // (when the auto_ptr deletes the key it removes itself from the map).  
 359             secdebug("freeKey", "CSPDL FreeKey"); 
 360                 auto_ptr
<SSKey
> ssKey(&mSSCSPDLSession
.find
<SSKey
>(ioKey
)); 
 361                 ssKey
->free(accessCred
, ioKey
, deleteKey
); 
 365                 CSPFullPluginSession::FreeKey(accessCred
, ioKey
, deleteKey
); 
 374 SSCSPSession::GenerateRandom(CSSM_CC_HANDLE ccHandle
, 
 375                                                          const Context 
&context
, 
 376                                                          CssmData 
&randomNumber
) 
 378     checkOperation(context
.type(), CSSM_ALGCLASS_RANDOMGEN
); 
 379         // if (context.algorithm() != @@@) CssmError::throwMe(ALGORITHM_NOT_SUPPORTED); 
 380         uint32 needed 
= context
.getInt(CSSM_ATTRIBUTE_OUTPUT_SIZE
, CSSMERR_CSP_MISSING_ATTR_OUTPUT_SIZE
); 
 382         // @@@ What about the seed? 
 383     if (randomNumber
.length()) 
 385         if (randomNumber
.length() < needed
) 
 386             CssmError::throwMe(CSSMERR_CSP_OUTPUT_LENGTH_ERROR
); 
 387                 randomNumber
.Length 
= needed
; 
 388                 clientSession().generateRandom(randomNumber
); 
 392         randomNumber
.Data 
= alloc
<uint8
>(needed
); 
 395                         randomNumber
.Length 
= needed
; 
 396                         clientSession().generateRandom(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 persistant 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 */