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 void aboutToDestruct();
143 bool operator ==(const KeychainImpl
&) const;
146 void add(Item
&item
);
147 void addCopy(Item
&item
);
148 void deleteItem(Item
&item
); // item must be persistent.
151 void create(UInt32 passwordLength
, const void *inPassword
);
152 void createWithBlob(CssmData
&blob
);
153 void create(ConstStringPtr inPassword
);
155 void create(const ResourceControlContext
*rcc
);
158 // Locking and unlocking a keychain.
161 void unlock(const CssmData
&password
);
162 void unlock(ConstStringPtr password
); // @@@ This has a length limit, we should remove it.
166 void getSettings(uint32
&outIdleTimeOut
, bool &outLockOnSleep
);
167 void setSettings(uint32 inIdleTimeOut
, bool inLockOnSleep
);
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
);
176 void authenticate(const CSSM_ACCESS_CREDENTIALS
*cred
); // Does not do an unlock.
178 const char *name() const { return mDb
->name(); }
179 UInt32
status() const;
181 bool isActive() const;
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(); }
189 CssmClient::CSP
csp();
191 PrimaryKey
makePrimaryKey(CSSM_DB_RECORDTYPE recordType
, CssmClient::DbUniqueRecord
&uniqueId
);
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
);
197 const CssmAutoDbRecordAttributeInfo
&primaryKeyInfosFor(CSSM_DB_RECORDTYPE recordType
);
199 Item
item(const PrimaryKey
& primaryKey
);
200 Item
item(CSSM_DB_RECORDTYPE recordType
, CssmClient::DbUniqueRecord
&uniqueId
);
202 // Check for an item that may have been deleted.
203 Item
itemdeleted(const PrimaryKey
& primaryKey
);
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();
210 void didDeleteItem(ItemImpl
*inItemImpl
);
212 void recode(const CssmData
&data
, const CssmData
&extraData
);
213 void copyBlob(CssmData
&dbBlob
);
215 void setBatchMode(Boolean mode
, Boolean rollBack
);
217 // yield default open() credentials for this keychain (as of now)
218 const AccessCredentials
*defaultCredentials();
220 // Only call these functions while holding globals().apiLock.
221 bool inCache() const _NOEXCEPT
{ return mInCache
; }
222 void inCache(bool inCache
) _NOEXCEPT
{ mInCache
= inCache
; }
224 void postEvent(SecKeychainEvent kcEvent
, ItemImpl
* item
);
225 void postEvent(SecKeychainEvent kcEvent
, ItemImpl
* item
, PrimaryKey pk
);
227 void addItem(const PrimaryKey
&primaryKey
, ItemImpl
*dbItemImpl
);
231 // Returns true if this keychain supports the attribute integrity and
232 // partition ID protections
233 bool hasIntegrityProtection();
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();
240 // Notify the keychain that you're accessing it. Used in conjunction with
241 // the StorageManager for time-based caching.
244 // Used by StorageManager to remember the timer->keychain pairing
245 dispatch_source_t mCacheTimer
;
247 // Set this to true to make tickling do nothing.
248 bool mSuppressTickle
;
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
);
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
);
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
);
262 // Remember if we've attempted to upgrade this keychain's database
263 bool mAttemptedUpgrade
;
265 void removeItem(const PrimaryKey
&primaryKey
, ItemImpl
*inItemImpl
);
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
);
273 // Looks up an item in the item cache.
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
);
280 // Looks up a deleted item in the deleted item map. Does not check the normal map.
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
);
287 const AccessCredentials
*makeCredentials();
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
;
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
;
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.
308 // True iff we are in the cache of keychains in StorageManager
313 KeychainSchema mKeychainSchema
;
315 // Data for auto-unlock credentials
316 DefaultCredentials mCustomUnlockCreds
;
318 EventBuffer
*mEventBuffer
;
319 mutable Mutex mMutex
;
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.
328 CFIndex
GetKeychainRetainCount(Keychain
& kc
);
330 class Keychain
: public SecPointer
<KeychainImpl
>
334 Keychain(KeychainImpl
*impl
) : SecPointer
<KeychainImpl
>(impl
) {}
337 static Keychain
optional(SecKeychainRef handle
);
340 friend class StorageManager
;
341 friend class KeychainImpl
;
342 friend class TrustKeychains
;
343 Keychain(const CssmClient::Db
&db
)
344 : SecPointer
<KeychainImpl
>(new KeychainImpl(db
)) {}
346 typedef KeychainImpl Impl
;
350 } // end namespace KeychainCore
352 } // end namespace Security
354 #endif // !_SECURITY_KEYCHAINS_H_