]>
Commit | Line | Data |
---|---|---|
d8f41ccd A |
1 | /* |
2 | * Copyright (c) 2000-2008,2012-2013 Apple Inc. All Rights Reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
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 | |
11 | * file. | |
12 | * | |
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. | |
20 | * | |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | */ | |
23 | ||
24 | ||
25 | // | |
26 | // kcdatabase - software database container implementation. | |
27 | // | |
28 | // A KeychainDatabase is a software storage container, | |
29 | // implemented in cooperation by the AppleCSLDP CDSA plugin and this daemon. | |
30 | // | |
31 | #ifndef _H_KCDATABASE | |
32 | #define _H_KCDATABASE | |
33 | ||
34 | #include "localdatabase.h" | |
35 | #include <securityd_client/ss_types.h> | |
5c19dc3a | 36 | #include "agentclient.h" |
d8f41ccd A |
37 | |
38 | class KeychainDatabase; | |
39 | class KeychainDbCommon; | |
40 | class KeychainKey; | |
41 | ||
42 | ||
43 | // | |
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. | |
47 | // | |
48 | class DbIdentifier { | |
49 | public: | |
50 | DbIdentifier(const DLDbIdentifier &id, DbBlob::Signature sig) | |
51 | : mIdent(id), mSig(sig) { } | |
52 | ||
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(); } | |
58 | ||
59 | bool operator < (const DbIdentifier &id) const // simple lexicographic | |
60 | { | |
61 | if (mIdent < id.mIdent) return true; | |
62 | if (id.mIdent < mIdent) return false; | |
63 | return mSig < id.mSig; | |
64 | } | |
65 | ||
66 | bool operator == (const DbIdentifier &id) const | |
67 | { return mIdent == id.mIdent && mSig == id.mSig; } | |
68 | ||
69 | private: | |
70 | DLDbIdentifier mIdent; | |
71 | DbBlob::Signature mSig; | |
72 | }; | |
73 | ||
74 | ||
75 | // | |
76 | // A vestigal system-global database instance | |
77 | // We don't (yet) use it for anything. Perhaps it should carry our ACL... | |
78 | // | |
79 | class KeychainDbGlobal : public PerGlobal { | |
80 | public: | |
81 | KeychainDbGlobal(const DbIdentifier &id); | |
82 | ~KeychainDbGlobal(); | |
83 | ||
84 | const DbIdentifier &identifier() const { return mIdentifier; } | |
85 | ||
86 | private: | |
87 | DbIdentifier mIdentifier; // database external identifier [const] | |
88 | }; | |
89 | ||
90 | ||
91 | // | |
92 | // KeychainDatabase DbCommons | |
93 | // | |
94 | class KeychainDbCommon : public LocalDbCommon, | |
95 | public DatabaseCryptoCore, public MachServer::Timer { | |
96 | public: | |
fa7225c8 A |
97 | KeychainDbCommon(Session &ssn, const DbIdentifier &id, uint32 requestedVersion = CommonBlob::version_none); |
98 | KeychainDbCommon(Session &ssn, const DbIdentifier &id, KeychainDbCommon& toClone); | |
d8f41ccd | 99 | ~KeychainDbCommon(); |
fa7225c8 A |
100 | |
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); | |
103 | ||
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(); | |
107 | ||
108 | void kill(); // remove from commonSet | |
d8f41ccd A |
109 | |
110 | KeychainDbGlobal &global() const; | |
111 | ||
112 | bool unlockDb(DbBlob *blob, void **privateAclBlob = NULL); | |
113 | void lockDb(); // make locked (if currently unlocked) | |
114 | bool isLocked() { return mIsLocked; } // lock status | |
115 | void setUnlocked(); | |
116 | void invalidateBlob() { version++; } | |
117 | ||
118 | void activity(); // reset lock timeout | |
119 | ||
120 | void makeNewSecrets(); | |
121 | ||
122 | const DbIdentifier &identifier() const {return mIdentifier; } | |
123 | const DLDbIdentifier &dlDbIdent() const { return identifier(); } | |
124 | const char *dbName() const { return dlDbIdent().dbName(); } | |
e3d460c9 | 125 | uint32 dbVersion() { return DatabaseCryptoCore::mBlobVersion; } |
d8f41ccd A |
126 | bool isLoginKeychain() const { return mLoginKeychain; } |
127 | ||
128 | DbBlob *encode(KeychainDatabase &db); | |
129 | ||
130 | void notify(NotificationEvent event) { DbCommon::notify(event, identifier()); } | |
131 | ||
132 | void sleepProcessing(); | |
133 | void lockProcessing(); | |
134 | ||
135 | bool belongsToSystem() const; | |
641423b6 | 136 | bool isDefaultSystemKeychain() const; |
d8f41ccd A |
137 | |
138 | public: | |
139 | // debugging | |
140 | IFDUMP(void dumpNode()); | |
141 | ||
142 | protected: | |
143 | void action(); // timer queue action to lock keychain | |
144 | ||
145 | // lifetime management for our Timer personality | |
146 | void select(); | |
147 | void unselect(); | |
148 | ||
149 | public: | |
150 | // all following data locked with object lock | |
151 | uint32 sequence; // change sequence number | |
152 | DBParameters mParams; // database parameters (arbitrated copy) | |
153 | ||
154 | uint32 version; // version stamp for change tracking | |
155 | ||
156 | private: | |
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 | |
161 | bool mLoginKeychain; | |
fa7225c8 A |
162 | |
163 | public: | |
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 | |
167 | ||
168 | private: | |
169 | void insertHoldingLock(); // Does the guts of insert(); you must hold a write lock on mRWCommonLock when calling this | |
170 | ||
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 | |
d8f41ccd A |
175 | }; |
176 | ||
177 | ||
178 | // | |
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 | |
181 | // access. | |
182 | // | |
183 | class KeychainDatabase : public LocalDatabase, private virtual SecurityServerAcl { | |
184 | friend class KeychainDbCommon; | |
185 | public: | |
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); | |
190 | ||
191 | // keychain synchronization recode to a specfic blob: | |
192 | KeychainDatabase(KeychainDatabase &src, Process &proc, DbHandle dbToClone); | |
e3d460c9 | 193 | |
fa7225c8 A |
194 | // Clone another database, but to a new DLDb identifier |
195 | KeychainDatabase(const DLDbIdentifier &id, KeychainDatabase &src, Process &proc); | |
196 | ||
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); | |
d8f41ccd A |
200 | virtual ~KeychainDatabase(); |
201 | ||
202 | KeychainDbCommon &common() const; | |
203 | const char *dbName() const; | |
204 | bool transient() const; | |
205 | ||
206 | KeychainDbGlobal &global() const { return common().global(); } | |
207 | ||
208 | public: | |
209 | static const int maxUnlockTryCount = 3; | |
210 | ||
211 | public: | |
212 | const DbIdentifier &identifier() const { return common().identifier(); } | |
213 | ||
214 | public: | |
215 | // encoding/decoding databases | |
216 | DbBlob *blob(); | |
217 | ||
218 | void authenticate(CSSM_DB_ACCESS_TYPE mode, const AccessCredentials *cred); | |
e3d460c9 | 219 | bool checkCredentials(const AccessCredentials* creds); |
d8f41ccd A |
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); | |
224 | ||
225 | // lock/unlock processing | |
226 | void lockDb(); // unconditional lock | |
fa7225c8 A |
227 | void unlockDb(bool unlockKeybag); // full-feature unlock |
228 | void unlockDb(const CssmData &passphrase, bool unlockKeybag); // unlock with passphrase | |
d8f41ccd A |
229 | |
230 | void stashDbCheck(); // check AppleKeyStore for master key | |
231 | void stashDb(); // stash master key in AppleKeyStore | |
232 | ||
233 | bool decode(); // unlock given established master key | |
234 | bool decode(const CssmData &passphrase); // set master key from PP, try unlock | |
235 | ||
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 | |
240 | ||
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; } | |
246 | ||
247 | // manage database parameters | |
248 | void setParameters(const DBParameters ¶ms); | |
249 | void getParameters(DBParameters ¶ms); | |
250 | ||
251 | // where's my (database) ACL? | |
252 | SecurityServerAcl &acl(); | |
253 | ||
254 | AclKind aclKind() const; | |
255 | Database *relatedDatabase(); | |
256 | ||
257 | // ACL state management hooks | |
258 | void instantiateAcl(); | |
259 | void changedAcl(); | |
260 | ||
261 | // miscellaneous utilities | |
262 | static void validateBlob(const DbBlob *blob); | |
263 | ||
fa7225c8 A |
264 | bool isRecoding(); |
265 | ||
266 | // Notify ourselves that the keychain recode/migration has finished | |
267 | void recodeFinished(); | |
268 | ||
d8f41ccd A |
269 | // debugging |
270 | IFDUMP(void dumpNode()); | |
271 | ||
272 | protected: | |
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); | |
275 | ||
fa7225c8 A |
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) | |
d8f41ccd A |
279 | |
280 | void establishOldSecrets(const AccessCredentials *creds); | |
b54c578e | 281 | bool establishNewSecrets(const AccessCredentials *creds, SecurityAgent::Reason reason, bool change); |
d8f41ccd A |
282 | |
283 | bool interactiveUnlock(); | |
284 | ||
285 | CssmClient::Key keyFromCreds(const TypedList &sample, unsigned int requiredLength); | |
866f8763 A |
286 | CssmClient::Key keyFromKeybag(const TypedList &sample); |
287 | CssmClient::Key makeRawKey(void *data, size_t length, CSSM_ALGORITHMS algid, CSSM_KEYUSE usage); | |
d8f41ccd A |
288 | |
289 | void encode(); // (re)generate mBlob if needed | |
fa7225c8 A |
290 | |
291 | // Counts the number of total interactive unlocks attempted by securityd | |
292 | static uint32_t interactiveUnlockAttempts; | |
293 | ||
294 | public: | |
295 | static uint32_t getInteractiveUnlockAttempts(); | |
d8f41ccd A |
296 | |
297 | private: | |
298 | // all following data is locked by the common lock | |
299 | bool mValidData; // valid ACL and params (blob decoded) | |
300 | CssmAutoData mSecret; | |
301 | bool mSaveSecret; | |
302 | ||
303 | uint32 version; // version stamp for blob validity | |
304 | DbBlob *mBlob; // database blob (encoded) | |
305 | ||
306 | AccessCredentials *mCred; // local access credentials (always valid) | |
307 | ||
308 | RefPointer<KeychainDatabase> mRecodingSource; // keychain synchronization ONLY; should not require accessors | |
fa7225c8 | 309 | bool mRecoded; // true once a recode completes, until recodeFinished is called |
d8f41ccd A |
310 | }; |
311 | ||
312 | #endif //_H_KCDATABASE |