2  * Copyright (c) 2000-2008,2012-2013 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 // kcdatabase - software database container implementation. 
  28 // A KeychainDatabase is a software storage container, 
  29 // implemented in cooperation by the AppleCSLDP CDSA plugin and this daemon. 
  34 #include "localdatabase.h" 
  35 #include <securityd_client/ss_types.h> 
  36 #include "agentclient.h" 
  38 class KeychainDatabase
; 
  39 class KeychainDbCommon
; 
  44 // We identify KeychainDatabases uniquely by a combination of 
  45 // a DLDbIdentifier and a database (blob) identifier. Equivalence 
  46 // by DbIdentifier is the criterion for parent-side merging. 
  50         DbIdentifier(const DLDbIdentifier 
&id
, DbBlob::Signature sig
) 
  51         : mIdent(id
), mSig(sig
) { } 
  53         const DLDbIdentifier 
&dlDbIdentifier() const { return mIdent
; } 
  54         const DbBlob::Signature 
&signature() const { return mSig
; } 
  55         operator const DLDbIdentifier 
&() const { return dlDbIdentifier(); } 
  56         operator const DbBlob::Signature 
&() const      { return signature(); } 
  57         const char *dbName() const                      { return mIdent
.dbName(); } 
  59         bool operator < (const DbIdentifier 
&id
) const  // simple lexicographic 
  61                 if (mIdent 
< id
.mIdent
) return true; 
  62                 if (id
.mIdent 
< mIdent
) return false; 
  63                 return mSig 
< id
.mSig
; 
  66         bool operator == (const DbIdentifier 
&id
) const 
  67         { return mIdent 
== id
.mIdent 
&& mSig 
== id
.mSig
; } 
  70         DLDbIdentifier mIdent
; 
  71         DbBlob::Signature mSig
; 
  76 // A vestigal system-global database instance 
  77 // We don't (yet) use it for anything. Perhaps it should carry our ACL... 
  79 class KeychainDbGlobal 
: public PerGlobal 
{ 
  81         KeychainDbGlobal(const DbIdentifier 
&id
); 
  84         const DbIdentifier 
&identifier() const { return mIdentifier
; } 
  87         DbIdentifier mIdentifier
;       // database external identifier [const] 
  92 // KeychainDatabase DbCommons 
  94 class KeychainDbCommon 
: public LocalDbCommon
,  
  95         public DatabaseCryptoCore
, public MachServer::Timer 
{ 
  97     KeychainDbCommon(Session 
&ssn
, const DbIdentifier 
&id
, uint32 requestedVersion 
= CommonBlob::version_none
); 
  98     KeychainDbCommon(Session 
&ssn
, const DbIdentifier 
&id
, KeychainDbCommon
& toClone
); 
 101     // If you have an existing KeychainDbCommon, and want to make it look a lot like that one 
 102     void cloneFrom(KeychainDbCommon
& toClone
, uint32 requestedVersion 
= CommonBlob::version_none
); 
 104     // finishes the initialization of this KeychainDbCommon. Do not call this 
 105     // while holding the mCommon lock, or you may get a multiprocess deadlock. 
 106     void initializeKeybag(); 
 108         void kill();                // remove from commonSet 
 110         KeychainDbGlobal 
&global() const; 
 112         bool unlockDb(DbBlob 
*blob
, void **privateAclBlob 
= NULL
); 
 113         void lockDb();                          // make locked (if currently unlocked) 
 114         bool isLocked()                 { return mIsLocked
; } // lock status 
 116         void invalidateBlob()   { version
++; } 
 118         void activity();                        // reset lock timeout 
 120         void makeNewSecrets(); 
 122         const DbIdentifier 
&identifier() const {return mIdentifier
; } 
 123         const DLDbIdentifier 
&dlDbIdent() const { return identifier(); } 
 124         const char *dbName() const { return dlDbIdent().dbName(); } 
 125     uint32 
dbVersion() { return DatabaseCryptoCore::mBlobVersion
; } 
 126     bool isLoginKeychain() const { return mLoginKeychain
; } 
 128         DbBlob 
*encode(KeychainDatabase 
&db
); 
 130         void notify(NotificationEvent event
) { DbCommon::notify(event
, identifier()); } 
 132         void sleepProcessing(); 
 133         void lockProcessing(); 
 135         bool belongsToSystem() const; 
 136     bool isDefaultSystemKeychain() const; 
 140     IFDUMP(void dumpNode()); 
 143         void action();                          // timer queue action to lock keychain 
 145         // lifetime management for our Timer personality 
 150         // all following data locked with object lock 
 151         uint32 sequence
;                        // change sequence number 
 152         DBParameters mParams
;           // database parameters (arbitrated copy) 
 154         uint32 version
;                         // version stamp for change tracking 
 157         DbIdentifier mIdentifier
;       // database external identifier [const] 
 158         // all following data protected by object lock 
 159         bool mIsLocked
;                         // logically locked 
 160         bool mValidParams
;                      // mParams has been set 
 164     void insert();              // insert into commonSet 
 165     static bool find(const DbIdentifier 
&ident
, Session 
&session
, RefPointer
<KeychainDbCommon
> &common
, 
 166             uint32 requestedVersion 
= CommonBlob::version_none
, KeychainDbCommon
* cloneFrom 
= NULL
); // find in commonSet 
 169     void insertHoldingLock();              // Does the guts of insert(); you must hold a write lock on mRWCommonLock when calling this 
 171     // global set of KeychainDbCommons for name unification 
 172     typedef std::set
<KeychainDbCommon 
*> CommonSet
; 
 173     static CommonSet mCommonSet
; 
 174     static ReadWriteLock mRWCommonLock
;           //protects only mCommonSet 
 179 // A Database object represents an Apple CSP/DL open database (DL/DB) object. 
 180 // It maintains its protected semantic state (including keys) and provides controlled 
 183 class KeychainDatabase 
: public LocalDatabase
, private virtual SecurityServerAcl 
{ 
 184         friend class KeychainDbCommon
; 
 186         KeychainDatabase(const DLDbIdentifier 
&id
, const DBParameters 
¶ms
, Process 
&proc
, 
 187         const AccessCredentials 
*cred
, const AclEntryPrototype 
*owner
); 
 188         KeychainDatabase(const DLDbIdentifier 
&id
, const DbBlob 
*blob
, Process 
&proc
, 
 189         const AccessCredentials 
*cred
); 
 191         // keychain synchronization recode to a specfic blob: 
 192         KeychainDatabase(KeychainDatabase 
&src
, Process 
&proc
, DbHandle dbToClone
); 
 194     // Clone another database, but to a new DLDb identifier 
 195     KeychainDatabase(const DLDbIdentifier 
&id
, KeychainDatabase 
&src
, Process 
&proc
); 
 197     // Copy another database, but with new secrets. 
 198     // To use this, you must provide the version you want to end up with. 
 199     KeychainDatabase(uint32 requestedVersion
, KeychainDatabase 
&src
, Process 
&proc
); 
 200         virtual ~KeychainDatabase(); 
 202         KeychainDbCommon 
&common() const; 
 203         const char *dbName() const; 
 204         bool transient() const; 
 206     KeychainDbGlobal 
&global() const { return common().global(); } 
 209         static const int maxUnlockTryCount 
= 3; 
 212     const DbIdentifier 
&identifier() const { return common().identifier(); } 
 215         // encoding/decoding databases 
 218     void authenticate(CSSM_DB_ACCESS_TYPE mode
, const AccessCredentials 
*cred
); 
 219     bool checkCredentials(const AccessCredentials
* creds
); 
 220     void changePassphrase(const AccessCredentials 
*cred
); 
 221         RefPointer
<Key
> extractMasterKey(Database 
&db
, const AccessCredentials 
*cred
, 
 222                 const AclEntryPrototype 
*owner
, uint32 usage
, uint32 attrs
); 
 223     void commitSecretsForSync(KeychainDatabase 
&cloneDb
); 
 225         // lock/unlock processing 
 226         void lockDb();                                                                                  // unconditional lock 
 227         void unlockDb(bool unlockKeybag
);                       // full-feature unlock 
 228         void unlockDb(const CssmData 
&passphrase
, bool unlockKeybag
);   // unlock with passphrase 
 230     void stashDbCheck();                                    // check AppleKeyStore for master key 
 231     void stashDb();                                         // stash master key in AppleKeyStore 
 233         bool decode();                                                                                  // unlock given established master key 
 234         bool decode(const CssmData 
&passphrase
);                                // set master key from PP, try unlock 
 236         bool validatePassphrase(const CssmData 
&passphrase
) const; // nonthrowing validation 
 237         bool isLocked()                 { return common().isLocked(); } // lock status 
 238     void notify(NotificationEvent event
) { return common().notify(event
); } 
 239     void activity() const       { common().activity(); }                // reset timeout clock 
 241         // encoding/decoding keys 
 242     void decodeKey(KeyBlob 
*blob
, CssmKey 
&key
, void * &pubAcl
, void * &privAcl
); 
 243         KeyBlob 
*encodeKey(const CssmKey 
&key
, const CssmData 
&pubAcl
, const CssmData 
&privAcl
); 
 244         KeyBlob 
*recodeKey(KeychainKey 
&oldKey
);         
 245     bool validBlob() const      { return mBlob 
&& version 
== common().version
; } 
 247         // manage database parameters 
 248         void setParameters(const DBParameters 
¶ms
); 
 249         void getParameters(DBParameters 
¶ms
); 
 251         // where's my (database) ACL? 
 252         SecurityServerAcl 
&acl(); 
 254         AclKind 
aclKind() const; 
 255         Database 
*relatedDatabase(); 
 257     // ACL state management hooks 
 258         void instantiateAcl(); 
 261         // miscellaneous utilities 
 262         static void validateBlob(const DbBlob 
*blob
); 
 266     // Notify ourselves that the keychain recode/migration has finished 
 267     void recodeFinished(); 
 270     IFDUMP(void dumpNode()); 
 273         RefPointer
<Key
> makeKey(const CssmKey 
&newKey
, uint32 moreAttributes
, const AclEntryPrototype 
*owner
); 
 274         RefPointer
<Key
> makeKey(Database 
&db
, const CssmKey 
&newKey
, uint32 moreAttributes
, const AclEntryPrototype 
*owner
); 
 276         void makeUnlocked(bool unlockKeybag
);   // interior version of unlock() 
 277         void makeUnlocked(const AccessCredentials 
*cred
, bool unlockKeybag
); // like () with explicit cred 
 278         void makeUnlocked(const CssmData 
&passphrase
, bool unlockKeybag
);        // interior version of unlock(CssmData) 
 280         void establishOldSecrets(const AccessCredentials 
*creds
); 
 281         bool establishNewSecrets(const AccessCredentials 
*creds
, SecurityAgent::Reason reason
); 
 283         bool interactiveUnlock(); 
 285         CssmClient::Key 
keyFromCreds(const TypedList 
&sample
, unsigned int requiredLength
); 
 287         void encode();                                                                  // (re)generate mBlob if needed 
 289     // Counts the number of total interactive unlocks attempted by securityd 
 290     static uint32_t interactiveUnlockAttempts
; 
 293     static uint32_t getInteractiveUnlockAttempts(); 
 296         // all following data is locked by the common lock 
 297     bool mValidData
;                            // valid ACL and params (blob decoded) 
 298     CssmAutoData mSecret
; 
 301     uint32 version
;                                     // version stamp for blob validity 
 302     DbBlob 
*mBlob
;                                      // database blob (encoded) 
 304     AccessCredentials 
*mCred
;           // local access credentials (always valid) 
 306         RefPointer
<KeychainDatabase
> mRecodingSource
;   // keychain synchronization ONLY; should not require accessors 
 307     bool mRecoded
;                  // true once a recode completes, until recodeFinished is called 
 310 #endif //_H_KCDATABASE