/ securityd / src / kcdatabase.h
kcdatabase.h
  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>
 36  #include "agentclient.h"
 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:
 97      KeychainDbCommon(Session &ssn, const DbIdentifier &id, uint32 requestedVersion = CommonBlob::version_none);
 98      KeychainDbCommon(Session &ssn, const DbIdentifier &id, KeychainDbCommon& toClone);
 99  	~KeychainDbCommon();
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
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(); }
125      uint32 dbVersion() { return DatabaseCryptoCore::mBlobVersion; }
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;
136      bool isDefaultSystemKeychain() const;
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;
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
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 &params, 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);
193  
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);
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);
219      bool checkCredentials(const AccessCredentials* creds);
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
227  	void unlockDb(bool unlockKeybag);                       // full-feature unlock
228  	void unlockDb(const CssmData &passphrase, bool unlockKeybag);	// unlock with passphrase
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 &params);
249  	void getParameters(DBParameters &params);
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  
264      bool isRecoding();
265  
266      // Notify ourselves that the keychain recode/migration has finished
267      void recodeFinished();
268  
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  
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)
279  	
280  	void establishOldSecrets(const AccessCredentials *creds);
281  	bool establishNewSecrets(const AccessCredentials *creds, SecurityAgent::Reason reason, bool change);
282  	
283  	bool interactiveUnlock();
284  	
285  	CssmClient::Key keyFromCreds(const TypedList &sample, unsigned int requiredLength);
286  	CssmClient::Key keyFromKeybag(const TypedList &sample);
287  	CssmClient::Key makeRawKey(void *data, size_t length, CSSM_ALGORITHMS algid, CSSM_KEYUSE usage);
288  	
289  	void encode();									// (re)generate mBlob if needed
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();
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
309      bool mRecoded;                  // true once a recode completes, until recodeFinished is called
310  };
311  
312  #endif //_H_KCDATABASE