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
, bool change
);
283 bool interactiveUnlock();
285 CssmClient::Key
keyFromCreds(const TypedList
&sample
, unsigned int requiredLength
);
286 CssmClient::Key
keyFromKeybag(const TypedList
&sample
);
287 CssmClient::Key
makeRawKey(void *data
, size_t length
, CSSM_ALGORITHMS algid
, CSSM_KEYUSE usage
);
289 void encode(); // (re)generate mBlob if needed
291 // Counts the number of total interactive unlocks attempted by securityd
292 static uint32_t interactiveUnlockAttempts
;
295 static uint32_t getInteractiveUnlockAttempts();
298 // all following data is locked by the common lock
299 bool mValidData
; // valid ACL and params (blob decoded)
300 CssmAutoData mSecret
;
303 uint32 version
; // version stamp for blob validity
304 DbBlob
*mBlob
; // database blob (encoded)
306 AccessCredentials
*mCred
; // local access credentials (always valid)
308 RefPointer
<KeychainDatabase
> mRecodingSource
; // keychain synchronization ONLY; should not require accessors
309 bool mRecoded
; // true once a recode completes, until recodeFinished is called
312 #endif //_H_KCDATABASE