2 * Copyright (c) 2000-2004,2011-2014 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@
25 // Keychains.h - The Keychain class
27 #ifndef _SECURITY_KEYCHAINS_H_
28 #define _SECURITY_KEYCHAINS_H_
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>
37 #include "SecCFTypes.h"
38 #include "defaultcreds.h"
45 namespace KeychainCore
53 class KeychainSchemaImpl
: public RefCount
55 NOCOPY(KeychainSchemaImpl
)
57 friend class KeychainSchema
;
59 KeychainSchemaImpl(const CssmClient::Db
&db
);
61 virtual ~KeychainSchemaImpl();
63 CSSM_DB_ATTRIBUTE_FORMAT
attributeFormatFor(CSSM_DB_RECORDTYPE recordType
, uint32 attributeId
) const;
64 const CssmAutoDbRecordAttributeInfo
&primaryKeyInfosFor(CSSM_DB_RECORDTYPE recordType
) const;
66 bool operator <(const KeychainSchemaImpl
&other
) const;
67 bool operator ==(const KeychainSchemaImpl
&other
) const;
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;
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
);
82 typedef map
<CSSM_DB_RECORDTYPE
, CssmAutoDbRecordAttributeInfo
*> PrimaryKeyInfoMap
;
83 PrimaryKeyInfoMap mPrimaryKeyInfoMap
;
85 typedef map
<uint32
, CSSM_DB_ATTRIBUTE_FORMAT
> RelationInfoMap
;
86 typedef map
<CSSM_DB_RECORDTYPE
, RelationInfoMap
> DatabaseInfoMap
;
87 DatabaseInfoMap mDatabaseInfoMap
;
91 const RelationInfoMap
&relationInfoMapFor(CSSM_DB_RECORDTYPE recordType
) const;
95 class KeychainSchema
: public RefPointer
<KeychainSchemaImpl
>
99 KeychainSchema(KeychainSchemaImpl
*impl
) : RefPointer
<KeychainSchemaImpl
>(impl
) {}
100 KeychainSchema(const CssmClient::Db
&db
) : RefPointer
<KeychainSchemaImpl
>(new KeychainSchemaImpl(db
)) {}
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
; }
109 typedef KeychainSchemaImpl Impl
;
115 class KeychainImpl
: public SecCFObject
, private CssmClient::Db::DefaultCredentialsMaker
119 SECCFFUNCTIONS(KeychainImpl
, SecKeychainRef
, errSecInvalidKeychain
, gTypes().KeychainImpl
)
121 friend class Keychain
;
122 friend class ItemImpl
;
123 friend class KeyItem
;
124 friend class KCCursorImpl
;
125 friend class StorageManager
;
127 KeychainImpl(const CssmClient::Db
&db
);
130 // Methods called by ItemImpl;
131 void didUpdate(const Item
&inItem
, PrimaryKey
&oldPK
,
133 void completeAdd(Item
&item
, PrimaryKey
&key
);
136 virtual ~KeychainImpl();
138 Mutex
* getKeychainMutex();
139 Mutex
* getMutexForObject() const;
141 ReadWriteLock
* getKeychainReadWriteLock();
142 void aboutToDestruct();
144 bool operator ==(const KeychainImpl
&) const;
147 void add(Item
&item
);
148 void addCopy(Item
&item
);
149 void deleteItem(Item
&item
); // item must be persistent.
152 void create(UInt32 passwordLength
, const void *inPassword
);
153 void createWithBlob(CssmData
&blob
);
154 void create(ConstStringPtr inPassword
);
156 void create(const ResourceControlContext
*rcc
);
159 // Locking and unlocking a keychain.
162 void unlock(const CssmData
&password
);
163 void unlock(ConstStringPtr password
); // @@@ This has a length limit, we should remove it.
167 void getSettings(uint32
&outIdleTimeOut
, bool &outLockOnSleep
);
168 void setSettings(uint32 inIdleTimeOut
, bool inLockOnSleep
);
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
);
177 void authenticate(const CSSM_ACCESS_CREDENTIALS
*cred
); // Does not do an unlock.
179 const char *name() const { return mDb
->name(); }
180 UInt32
status() const;
182 bool isActive() const;
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(); }
190 CssmClient::CSP
csp();
192 PrimaryKey
makePrimaryKey(CSSM_DB_RECORDTYPE recordType
, CssmClient::DbUniqueRecord
&uniqueId
);
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
);
198 const CssmAutoDbRecordAttributeInfo
&primaryKeyInfosFor(CSSM_DB_RECORDTYPE recordType
);
200 Item
item(const PrimaryKey
& primaryKey
);
201 Item
item(CSSM_DB_RECORDTYPE recordType
, CssmClient::DbUniqueRecord
&uniqueId
);
203 // Check for an item that may have been deleted.
204 Item
itemdeleted(const PrimaryKey
& primaryKey
);
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();
211 void didDeleteItem(ItemImpl
*inItemImpl
);
213 void recode(const CssmData
&data
, const CssmData
&extraData
);
214 void copyBlob(CssmData
&dbBlob
);
216 void setBatchMode(Boolean mode
, Boolean rollBack
);
218 // yield default open() credentials for this keychain (as of now)
219 const AccessCredentials
*defaultCredentials();
221 // Only call these functions while holding globals().apiLock.
222 bool inCache() const throw() { return mInCache
; }
223 void inCache(bool inCache
) throw() { mInCache
= inCache
; }
225 void postEvent(SecKeychainEvent kcEvent
, ItemImpl
* item
);
226 void postEvent(SecKeychainEvent kcEvent
, ItemImpl
* item
, PrimaryKey pk
);
228 void addItem(const PrimaryKey
&primaryKey
, ItemImpl
*dbItemImpl
);
232 // Returns true if this keychain supports the attribute integrity and
233 // partition ID protections
234 bool hasIntegrityProtection();
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();
241 // Notify the keychain that you're accessing it. Used in conjunction with
242 // the StorageManager for time-based caching.
245 // Used by StorageManager to remember the timer->keychain pairing
246 dispatch_source_t mCacheTimer
;
248 // Set this to true to make tickling do nothing.
249 bool mSuppressTickle
;
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
);
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
);
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
);
263 // Remember if we've attempted to upgrade this keychain's database
264 bool mAttemptedUpgrade
;
266 void removeItem(const PrimaryKey
&primaryKey
, ItemImpl
*inItemImpl
);
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
);
274 // Looks up an item in the item cache.
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
);
281 // Looks up a deleted item in the deleted item map. Does not check the normal map.
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
);
288 const AccessCredentials
*makeCredentials();
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
;
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
;
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.
309 // True iff we are in the cache of keychains in StorageManager
314 KeychainSchema mKeychainSchema
;
316 // Data for auto-unlock credentials
317 DefaultCredentials mCustomUnlockCreds
;
319 EventBuffer
*mEventBuffer
;
320 mutable Mutex mMutex
;
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.
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
;
334 CFIndex
GetKeychainRetainCount(Keychain
& kc
);
336 class Keychain
: public SecPointer
<KeychainImpl
>
340 Keychain(KeychainImpl
*impl
) : SecPointer
<KeychainImpl
>(impl
) {}
343 static Keychain
optional(SecKeychainRef handle
);
346 friend class StorageManager
;
347 friend class KeychainImpl
;
348 friend class TrustKeychains
;
349 Keychain(const CssmClient::Db
&db
)
350 : SecPointer
<KeychainImpl
>(new KeychainImpl(db
)) {}
352 typedef KeychainImpl Impl
;
356 } // end namespace KeychainCore
358 } // end namespace Security
360 #endif // !_SECURITY_KEYCHAINS_H_