]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/lib/Keychains.h
Security-57740.60.18.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / lib / Keychains.h
1 /*
2 * Copyright (c) 2000-2004,2011-2014 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 // Keychains.h - The Keychain class
26 //
27 #ifndef _SECURITY_KEYCHAINS_H_
28 #define _SECURITY_KEYCHAINS_H_
29
30 #include <security_cdsa_client/cspclient.h>
31 #include <security_cdsa_client/dlclient.h>
32 #include <security_utilities/refcount.h>
33 #include <security_utilities/seccfobject.h>
34 #include <Security/SecKeychain.h>
35 #include <Security/SecKeychainItem.h>
36 #include <memory>
37 #include "SecCFTypes.h"
38 #include "defaultcreds.h"
39
40 class EventBuffer;
41
42 namespace Security
43 {
44
45 namespace KeychainCore
46 {
47
48 class KCCursor;
49 class Item;
50 class PrimaryKey;
51 class StorageManager;
52
53 class KeychainSchemaImpl : public RefCount
54 {
55 NOCOPY(KeychainSchemaImpl)
56 public:
57 friend class KeychainSchema;
58 protected:
59 KeychainSchemaImpl(const CssmClient::Db &db);
60 public:
61 virtual ~KeychainSchemaImpl();
62
63 CSSM_DB_ATTRIBUTE_FORMAT attributeFormatFor(CSSM_DB_RECORDTYPE recordType, uint32 attributeId) const;
64 const CssmAutoDbRecordAttributeInfo &primaryKeyInfosFor(CSSM_DB_RECORDTYPE recordType) const;
65
66 bool operator <(const KeychainSchemaImpl &other) const;
67 bool operator ==(const KeychainSchemaImpl &other) const;
68
69 void getAttributeInfoForRecordType(CSSM_DB_RECORDTYPE recordType, SecKeychainAttributeInfo **Info) const;
70 CssmDbAttributeInfo attributeInfoFor(CSSM_DB_RECORDTYPE recordType, uint32 attributeId) const;
71 bool hasAttribute(CSSM_DB_RECORDTYPE recordType, uint32 attributeId) const;
72 bool hasRecordType(CSSM_DB_RECORDTYPE recordType) const;
73
74 void didCreateRelation(CSSM_DB_RECORDTYPE inRelationID,
75 const char *inRelationName,
76 uint32 inNumberOfAttributes,
77 const CSSM_DB_SCHEMA_ATTRIBUTE_INFO *pAttributeInfo,
78 uint32 inNumberOfIndexes,
79 const CSSM_DB_SCHEMA_INDEX_INFO *pIndexInfo);
80
81 private:
82 typedef map<CSSM_DB_RECORDTYPE, CssmAutoDbRecordAttributeInfo *> PrimaryKeyInfoMap;
83 PrimaryKeyInfoMap mPrimaryKeyInfoMap;
84
85 typedef map<uint32, CSSM_DB_ATTRIBUTE_FORMAT> RelationInfoMap;
86 typedef map<CSSM_DB_RECORDTYPE, RelationInfoMap> DatabaseInfoMap;
87 DatabaseInfoMap mDatabaseInfoMap;
88 Mutex mMutex;
89
90 private:
91 const RelationInfoMap &relationInfoMapFor(CSSM_DB_RECORDTYPE recordType) const;
92 };
93
94
95 class KeychainSchema : public RefPointer<KeychainSchemaImpl>
96 {
97 public:
98 KeychainSchema() {}
99 KeychainSchema(KeychainSchemaImpl *impl) : RefPointer<KeychainSchemaImpl>(impl) {}
100 KeychainSchema(const CssmClient::Db &db) : RefPointer<KeychainSchemaImpl>(new KeychainSchemaImpl(db)) {}
101 ~KeychainSchema();
102
103 bool operator <(const KeychainSchema &other) const
104 { return ptr && other.ptr ? *ptr < *other.ptr : ptr < other.ptr; }
105 bool operator ==(const KeychainSchema &other) const
106 { return ptr && other.ptr ? *ptr == *other.ptr : ptr == other.ptr; }
107
108 private:
109 typedef KeychainSchemaImpl Impl;
110 };
111
112
113 class ItemImpl;
114
115 class KeychainImpl : public SecCFObject, private CssmClient::Db::DefaultCredentialsMaker
116 {
117 NOCOPY(KeychainImpl)
118 public:
119 SECCFFUNCTIONS(KeychainImpl, SecKeychainRef, errSecInvalidKeychain, gTypes().KeychainImpl)
120
121 friend class Keychain;
122 friend class ItemImpl;
123 friend class KeyItem;
124 friend class KCCursorImpl;
125 friend class StorageManager;
126 protected:
127 KeychainImpl(const CssmClient::Db &db);
128
129 protected:
130 // Methods called by ItemImpl;
131 void didUpdate(const Item &inItem, PrimaryKey &oldPK,
132 PrimaryKey &newPK);
133 void completeAdd(Item &item, PrimaryKey &key);
134
135 public:
136 virtual ~KeychainImpl();
137
138 Mutex* getKeychainMutex();
139 Mutex* getMutexForObject() const;
140
141 ReadWriteLock* getKeychainReadWriteLock();
142 void aboutToDestruct();
143
144 bool operator ==(const KeychainImpl &) const;
145
146 // Item calls
147 void add(Item &item);
148 void addCopy(Item &item);
149 void deleteItem(Item &item); // item must be persistent.
150
151 // Keychain calls
152 void create(UInt32 passwordLength, const void *inPassword);
153 void createWithBlob(CssmData &blob);
154 void create(ConstStringPtr inPassword);
155 void create();
156 void create(const ResourceControlContext *rcc);
157 void open();
158
159 // Locking and unlocking a keychain.
160 void lock();
161 void unlock();
162 void unlock(const CssmData &password);
163 void unlock(ConstStringPtr password); // @@@ This has a length limit, we should remove it.
164 void stash();
165 void stashCheck();
166
167 void getSettings(uint32 &outIdleTimeOut, bool &outLockOnSleep);
168 void setSettings(uint32 inIdleTimeOut, bool inLockOnSleep);
169
170 // Passing in NULL for either oldPassword or newPassword will cause them to be prompted for.
171 // To specify a zero length password in either case the oldPasswordLength or newPasswordLength
172 // value must be 0 and the oldPassword or newPassword must not be NULL.
173 void changePassphrase(UInt32 oldPasswordLength, const void *oldPassword,
174 UInt32 newPasswordLength, const void *newPassword);
175 void changePassphrase(ConstStringPtr oldPassword, ConstStringPtr newPassword);
176
177 void authenticate(const CSSM_ACCESS_CREDENTIALS *cred); // Does not do an unlock.
178
179 const char *name() const { return mDb->name(); }
180 UInt32 status() const;
181 bool exists();
182 bool isActive() const;
183
184 KCCursor createCursor(const SecKeychainAttributeList *attrList);
185 KCCursor createCursor(SecItemClass itemClass, const SecKeychainAttributeList *attrList);
186 CssmClient::Db database() { StLock<Mutex>_(mDbMutex); return mDb; }
187 void changeDatabase(CssmClient::Db db);
188 DLDbIdentifier dlDbIdentifier() const { return mDb->dlDbIdentifier(); }
189
190 CssmClient::CSP csp();
191
192 PrimaryKey makePrimaryKey(CSSM_DB_RECORDTYPE recordType, CssmClient::DbUniqueRecord &uniqueId);
193
194 // This will make a primary key for this record type, and populate it completely from the given attributes
195 PrimaryKey makePrimaryKey(CSSM_DB_RECORDTYPE recordType, CssmClient::DbAttributes *currentAttributes);
196 void gatherPrimaryKeyAttributes(CssmClient::DbAttributes& primaryKeyAttrs);
197
198 const CssmAutoDbRecordAttributeInfo &primaryKeyInfosFor(CSSM_DB_RECORDTYPE recordType);
199
200 Item item(const PrimaryKey& primaryKey);
201 Item item(CSSM_DB_RECORDTYPE recordType, CssmClient::DbUniqueRecord &uniqueId);
202
203 // Check for an item that may have been deleted.
204 Item itemdeleted(const PrimaryKey& primaryKey);
205
206 CssmDbAttributeInfo attributeInfoFor(CSSM_DB_RECORDTYPE recordType, UInt32 tag);
207 void getAttributeInfoForItemID(CSSM_DB_RECORDTYPE itemID, SecKeychainAttributeInfo **Info);
208 static void freeAttributeInfo(SecKeychainAttributeInfo *Info);
209 KeychainSchema keychainSchema();
210 void resetSchema();
211 void didDeleteItem(ItemImpl *inItemImpl);
212
213 void recode(const CssmData &data, const CssmData &extraData);
214 void copyBlob(CssmData &dbBlob);
215
216 void setBatchMode(Boolean mode, Boolean rollBack);
217
218 // yield default open() credentials for this keychain (as of now)
219 const AccessCredentials *defaultCredentials();
220
221 // Only call these functions while holding globals().apiLock.
222 bool inCache() const throw() { return mInCache; }
223 void inCache(bool inCache) throw() { mInCache = inCache; }
224
225 void postEvent(SecKeychainEvent kcEvent, ItemImpl* item);
226 void postEvent(SecKeychainEvent kcEvent, ItemImpl* item, PrimaryKey pk);
227
228 void addItem(const PrimaryKey &primaryKey, ItemImpl *dbItemImpl);
229
230 bool mayDelete();
231
232 // Returns true if this keychain supports the attribute integrity and
233 // partition ID protections
234 bool hasIntegrityProtection();
235
236 private:
237 // Checks for and triggers a keychain database upgrade
238 // DO NOT hold any of the keychain locks when you call this
239 bool performKeychainUpgradeIfNeeded();
240
241 // Notify the keychain that you're accessing it. Used in conjunction with
242 // the StorageManager for time-based caching.
243 void tickle();
244
245 // Used by StorageManager to remember the timer->keychain pairing
246 dispatch_source_t mCacheTimer;
247
248 // Set this to true to make tickling do nothing.
249 bool mSuppressTickle;
250
251 public:
252 // Grab the locks and then call attemptKeychainMigration
253 // The access credentials are only used when downgrading version, and will be passed along with ACL edits
254 bool keychainMigration(const string oldPath, const uint32 dbBlobVersion, const string newPath, const uint32 newBlobVersion, const AccessCredentials *cred = NULL);
255
256 private:
257 // Attempt to upgrade this keychain's database
258 uint32 attemptKeychainMigration(const string oldPath, const uint32 oldBlobVersion, const string newPath, const uint32 newBlobVersion, const AccessCredentials *cred);
259
260 // Attempt to rename this keychain, if someone hasn't beaten us to it
261 void attemptKeychainRename(const string oldPath, const string newPath, uint32 blobVersion);
262
263 // Remember if we've attempted to upgrade this keychain's database
264 bool mAttemptedUpgrade;
265
266 void removeItem(const PrimaryKey &primaryKey, ItemImpl *inItemImpl);
267
268 // Use this when you want to be extra sure this item is removed from the
269 // cache. Iterates over the whole cache to find all instances. This function
270 // will take both cache map mutexes, so you must not hold only the
271 // mDbDeletedItemMapMutex when you call this function.
272 void forceRemoveFromCache(ItemImpl* inItemImpl);
273
274 // Looks up an item in the item cache.
275 //
276 // To use this in a thread-safe manner, you must hold this keychain's mutex
277 // from before you begin this operation until you have safely completed a
278 // CFRetain on the resulting ItemImpl.
279 ItemImpl *_lookupItem(const PrimaryKey &primaryKey);
280
281 // Looks up a deleted item in the deleted item map. Does not check the normal map.
282 //
283 // To use this in a thread-safe manner, you must hold this keychain's mutex
284 // from before you begin this operation until you have safely completed a
285 // CFRetain on the resulting ItemImpl.
286 ItemImpl *_lookupDeletedItemOnly(const PrimaryKey &primaryKey);
287
288 const AccessCredentials *makeCredentials();
289
290 typedef map<PrimaryKey, ItemImpl *> DbItemMap;
291 // Reference map of all items we know about that have a primaryKey
292 DbItemMap mDbItemMap;
293 Mutex mDbItemMapMutex;
294
295 // Reference map of all items we know about that have been deleted
296 // but we haven't yet received a deleted notification about.
297 // We need this for when we delete an item (and so don't want it anymore)
298 // but stil need the item around to pass along to the client process with the
299 // deletion notification (if they've registered for such things).
300 DbItemMap mDbDeletedItemMap;
301 Mutex mDbDeletedItemMapMutex;
302
303 // Note on ItemMapMutexes: STL maps are not thread-safe, so you must hold the
304 // mutex for the entire duration of your access/modification to the map.
305 // Otherwise, other processes might interrupt your iterator by adding/removing
306 // items. If you must hold both mutexes, you must take mDbItemMapMutex before
307 // mDbDeletedItemMapMutex.
308
309 // True iff we are in the cache of keychains in StorageManager
310 bool mInCache;
311
312 CssmClient::Db mDb;
313
314 KeychainSchema mKeychainSchema;
315
316 // Data for auto-unlock credentials
317 DefaultCredentials mCustomUnlockCreds;
318 bool mIsInBatchMode;
319 EventBuffer *mEventBuffer;
320 mutable Mutex mMutex;
321
322 // Now that we sometimes change the database object, Db object
323 // creation/returning needs a mutex. You should only hold this if you're
324 // copying or changing the mDb object.
325 Mutex mDbMutex;
326
327 // Used to protect mDb across calls.
328 // Grab a read lock if you expect to read from this keychain in the future.
329 // The write lock is taken if we're replacing the database wholesale with something new.
330 ReadWriteLock mRWLock;
331 };
332
333
334 CFIndex GetKeychainRetainCount(Keychain& kc);
335
336 class Keychain : public SecPointer<KeychainImpl>
337 {
338 public:
339 Keychain();
340 Keychain(KeychainImpl *impl) : SecPointer<KeychainImpl>(impl) {}
341 ~Keychain();
342
343 static Keychain optional(SecKeychainRef handle);
344
345 private:
346 friend class StorageManager;
347 friend class KeychainImpl;
348 friend class TrustKeychains;
349 Keychain(const CssmClient::Db &db)
350 : SecPointer<KeychainImpl>(new KeychainImpl(db)) {}
351
352 typedef KeychainImpl Impl;
353 };
354
355
356 } // end namespace KeychainCore
357
358 } // end namespace Security
359
360 #endif // !_SECURITY_KEYCHAINS_H_