]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/lib/Keychains.h
Security-59754.41.1.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 void aboutToDestruct();
142
143 bool operator ==(const KeychainImpl &) const;
144
145 // Item calls
146 void add(Item &item);
147 void addCopy(Item &item);
148 void deleteItem(Item &item); // item must be persistent.
149
150 // Keychain calls
151 void create(UInt32 passwordLength, const void *inPassword);
152 void createWithBlob(CssmData &blob);
153 void create(ConstStringPtr inPassword);
154 void create();
155 void create(const ResourceControlContext *rcc);
156 void open();
157
158 // Locking and unlocking a keychain.
159 void lock();
160 void unlock();
161 void unlock(const CssmData &password);
162 void unlock(ConstStringPtr password); // @@@ This has a length limit, we should remove it.
163 void stash();
164 void stashCheck();
165
166 void getSettings(uint32 &outIdleTimeOut, bool &outLockOnSleep);
167 void setSettings(uint32 inIdleTimeOut, bool inLockOnSleep);
168
169 // Passing in NULL for either oldPassword or newPassword will cause them to be prompted for.
170 // To specify a zero length password in either case the oldPasswordLength or newPasswordLength
171 // value must be 0 and the oldPassword or newPassword must not be NULL.
172 void changePassphrase(UInt32 oldPasswordLength, const void *oldPassword,
173 UInt32 newPasswordLength, const void *newPassword);
174 void changePassphrase(ConstStringPtr oldPassword, ConstStringPtr newPassword);
175
176 void authenticate(const CSSM_ACCESS_CREDENTIALS *cred); // Does not do an unlock.
177
178 const char *name() const { return mDb->name(); }
179 UInt32 status() const;
180 bool exists();
181 bool isActive() const;
182
183 KCCursor createCursor(const SecKeychainAttributeList *attrList);
184 KCCursor createCursor(SecItemClass itemClass, const SecKeychainAttributeList *attrList);
185 CssmClient::Db database() { StLock<Mutex>_(mDbMutex); return mDb; }
186 void changeDatabase(CssmClient::Db db);
187 DLDbIdentifier dlDbIdentifier() const { return mDb->dlDbIdentifier(); }
188
189 CssmClient::CSP csp();
190
191 PrimaryKey makePrimaryKey(CSSM_DB_RECORDTYPE recordType, CssmClient::DbUniqueRecord &uniqueId);
192
193 // This will make a primary key for this record type, and populate it completely from the given attributes
194 PrimaryKey makePrimaryKey(CSSM_DB_RECORDTYPE recordType, CssmClient::DbAttributes *currentAttributes);
195 void gatherPrimaryKeyAttributes(CssmClient::DbAttributes& primaryKeyAttrs);
196
197 const CssmAutoDbRecordAttributeInfo &primaryKeyInfosFor(CSSM_DB_RECORDTYPE recordType);
198
199 Item item(const PrimaryKey& primaryKey);
200 Item item(CSSM_DB_RECORDTYPE recordType, CssmClient::DbUniqueRecord &uniqueId);
201
202 // Check for an item that may have been deleted.
203 Item itemdeleted(const PrimaryKey& primaryKey);
204
205 CssmDbAttributeInfo attributeInfoFor(CSSM_DB_RECORDTYPE recordType, UInt32 tag);
206 void getAttributeInfoForItemID(CSSM_DB_RECORDTYPE itemID, SecKeychainAttributeInfo **Info);
207 static void freeAttributeInfo(SecKeychainAttributeInfo *Info);
208 KeychainSchema keychainSchema();
209 void resetSchema();
210 void didDeleteItem(ItemImpl *inItemImpl);
211
212 void recode(const CssmData &data, const CssmData &extraData);
213 void copyBlob(CssmData &dbBlob);
214
215 void setBatchMode(Boolean mode, Boolean rollBack);
216
217 // yield default open() credentials for this keychain (as of now)
218 const AccessCredentials *defaultCredentials();
219
220 // Only call these functions while holding globals().apiLock.
221 bool inCache() const _NOEXCEPT { return mInCache; }
222 void inCache(bool inCache) _NOEXCEPT { mInCache = inCache; }
223
224 void postEvent(SecKeychainEvent kcEvent, ItemImpl* item);
225 void postEvent(SecKeychainEvent kcEvent, ItemImpl* item, PrimaryKey pk);
226
227 void addItem(const PrimaryKey &primaryKey, ItemImpl *dbItemImpl);
228
229 bool mayDelete();
230
231 // Returns true if this keychain supports the attribute integrity and
232 // partition ID protections
233 bool hasIntegrityProtection();
234
235 private:
236 // Checks for and triggers a keychain database upgrade
237 // DO NOT hold any of the keychain locks when you call this
238 bool performKeychainUpgradeIfNeeded();
239
240 // Notify the keychain that you're accessing it. Used in conjunction with
241 // the StorageManager for time-based caching.
242 void tickle();
243
244 // Used by StorageManager to remember the timer->keychain pairing
245 dispatch_source_t mCacheTimer;
246
247 // Set this to true to make tickling do nothing.
248 bool mSuppressTickle;
249
250 public:
251 // Grab the locks and then call attemptKeychainMigration
252 // The access credentials are only used when downgrading version, and will be passed along with ACL edits
253 bool keychainMigration(const string oldPath, const uint32 dbBlobVersion, const string newPath, const uint32 newBlobVersion, const AccessCredentials *cred = NULL);
254
255 private:
256 // Attempt to upgrade this keychain's database
257 uint32 attemptKeychainMigration(const string oldPath, const uint32 oldBlobVersion, const string newPath, const uint32 newBlobVersion, const AccessCredentials *cred);
258
259 // Attempt to rename this keychain, if someone hasn't beaten us to it
260 void attemptKeychainRename(const string oldPath, const string newPath, uint32 blobVersion);
261
262 // Remember if we've attempted to upgrade this keychain's database
263 bool mAttemptedUpgrade;
264
265 void removeItem(const PrimaryKey &primaryKey, ItemImpl *inItemImpl);
266
267 // Use this when you want to be extra sure this item is removed from the
268 // cache. Iterates over the whole cache to find all instances. This function
269 // will take both cache map mutexes, so you must not hold only the
270 // mDbDeletedItemMapMutex when you call this function.
271 void forceRemoveFromCache(ItemImpl* inItemImpl);
272
273 // Looks up an item in the item cache.
274 //
275 // To use this in a thread-safe manner, you must hold this keychain's mutex
276 // from before you begin this operation until you have safely completed a
277 // CFRetain on the resulting ItemImpl.
278 ItemImpl *_lookupItem(const PrimaryKey &primaryKey);
279
280 // Looks up a deleted item in the deleted item map. Does not check the normal map.
281 //
282 // To use this in a thread-safe manner, you must hold this keychain's mutex
283 // from before you begin this operation until you have safely completed a
284 // CFRetain on the resulting ItemImpl.
285 ItemImpl *_lookupDeletedItemOnly(const PrimaryKey &primaryKey);
286
287 const AccessCredentials *makeCredentials();
288
289 typedef map<PrimaryKey, ItemImpl *> DbItemMap;
290 // Reference map of all items we know about that have a primaryKey
291 DbItemMap mDbItemMap;
292 Mutex mDbItemMapMutex;
293
294 // Reference map of all items we know about that have been deleted
295 // but we haven't yet received a deleted notification about.
296 // We need this for when we delete an item (and so don't want it anymore)
297 // but stil need the item around to pass along to the client process with the
298 // deletion notification (if they've registered for such things).
299 DbItemMap mDbDeletedItemMap;
300 Mutex mDbDeletedItemMapMutex;
301
302 // Note on ItemMapMutexes: STL maps are not thread-safe, so you must hold the
303 // mutex for the entire duration of your access/modification to the map.
304 // Otherwise, other processes might interrupt your iterator by adding/removing
305 // items. If you must hold both mutexes, you must take mDbItemMapMutex before
306 // mDbDeletedItemMapMutex.
307
308 // True iff we are in the cache of keychains in StorageManager
309 bool mInCache;
310
311 CssmClient::Db mDb;
312
313 KeychainSchema mKeychainSchema;
314
315 // Data for auto-unlock credentials
316 DefaultCredentials mCustomUnlockCreds;
317 bool mIsInBatchMode;
318 EventBuffer *mEventBuffer;
319 mutable Mutex mMutex;
320
321 // Now that we sometimes change the database object, Db object
322 // creation/returning needs a mutex. You should only hold this if you're
323 // copying or changing the mDb object.
324 Mutex mDbMutex;
325 };
326
327
328 CFIndex GetKeychainRetainCount(Keychain& kc);
329
330 class Keychain : public SecPointer<KeychainImpl>
331 {
332 public:
333 Keychain();
334 Keychain(KeychainImpl *impl) : SecPointer<KeychainImpl>(impl) {}
335 ~Keychain();
336
337 static Keychain optional(SecKeychainRef handle);
338
339 private:
340 friend class StorageManager;
341 friend class KeychainImpl;
342 friend class TrustKeychains;
343 Keychain(const CssmClient::Db &db)
344 : SecPointer<KeychainImpl>(new KeychainImpl(db)) {}
345
346 typedef KeychainImpl Impl;
347 };
348
349
350 } // end namespace KeychainCore
351
352 } // end namespace Security
353
354 #endif // !_SECURITY_KEYCHAINS_H_