1/*
2 * Copyright (c) 2000-2007 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
37class KeychainDatabase;
38class KeychainDbCommon;
39class KeychainKey;
40
41
42//
43// We identify KeychainDatabases uniquely by a combination of
44// a DLDbIdentifier and a database (blob) identifier. Equivalence
45// by DbIdentifier is the criterion for parent-side merging.
46//
47class DbIdentifier {
48public:
49	DbIdentifier(const DLDbIdentifier &id, DbBlob::Signature sig)
50	: mIdent(id), mSig(sig) { }
51
52	const DLDbIdentifier &dlDbIdentifier() const { return mIdent; }
53	const DbBlob::Signature &signature() const { return mSig; }
54	operator const DLDbIdentifier &() const { return dlDbIdentifier(); }
55	operator const DbBlob::Signature &() const	{ return signature(); }
56	const char *dbName() const			{ return mIdent.dbName(); }
57
58	bool operator < (const DbIdentifier &id) const	// simple lexicographic
59	{
60		if (mIdent < id.mIdent) return true;
61		if (id.mIdent < mIdent) return false;
62		return mSig < id.mSig;
63	}
64
65	bool operator == (const DbIdentifier &id) const
66	{ return mIdent == id.mIdent && mSig == id.mSig; }
67
68private:
69	DLDbIdentifier mIdent;
70	DbBlob::Signature mSig;
71};
72
73
74//
75// A vestigal system-global database instance
76// We don't (yet) use it for anything. Perhaps it should carry our ACL...
77//
78class KeychainDbGlobal : public PerGlobal {
79public:
80	KeychainDbGlobal(const DbIdentifier &id);
81	~KeychainDbGlobal();
82
83	const DbIdentifier &identifier() const { return mIdentifier; }
84
85private:
86	DbIdentifier mIdentifier;	// database external identifier [const]
87};
88
89
90//
91// KeychainDatabase DbCommons
92//
93class KeychainDbCommon : public LocalDbCommon,
94	public DatabaseCryptoCore, public MachServer::Timer {
95public:
96	KeychainDbCommon(Session &ssn, const DbIdentifier &id);
97	~KeychainDbCommon();
98
99	KeychainDbGlobal &global() const;
100
101	bool unlockDb(DbBlob *blob, void **privateAclBlob = NULL);
102	void lockDb();				// make locked (if currently unlocked)
103	bool isLocked()			{ return mIsLocked; } // lock status
104	void setUnlocked();
105	void invalidateBlob()	{ version++; }
106
107	void activity();			// reset lock timeout
108
109	void makeNewSecrets();
110
111	const DbIdentifier &identifier() const {return mIdentifier; }
112	const DLDbIdentifier &dlDbIdent() const { return identifier(); }
113	const char *dbName() const { return dlDbIdent().dbName(); }
114    bool isLoginKeychain() const { return mLoginKeychain; }
115
116	DbBlob *encode(KeychainDatabase &db);
117
118	void notify(NotificationEvent event) { DbCommon::notify(event, identifier()); }
119
120	void sleepProcessing();
121	void lockProcessing();
122
123	bool belongsToSystem() const;
124
125public:
126    // debugging
127    IFDUMP(void dumpNode());
128
129protected:
130	void action();				// timer queue action to lock keychain
131
132	// lifetime management for our Timer personality
133	void select();
134	void unselect();
135
136public:
137	// all following data locked with object lock
138	uint32 sequence;			// change sequence number
139	DBParameters mParams;		// database parameters (arbitrated copy)
140
141	uint32 version;				// version stamp for change tracking
142
143private:
144	DbIdentifier mIdentifier;	// database external identifier [const]
145	// all following data protected by object lock
146	bool mIsLocked;				// logically locked
147	bool mValidParams;			// mParams has been set
148    bool mLoginKeychain;
149};
150
151
152//
153// A Database object represents an Apple CSP/DL open database (DL/DB) object.
154// It maintains its protected semantic state (including keys) and provides controlled
155// access.
156//
157class KeychainDatabase : public LocalDatabase, private virtual SecurityServerAcl {
158	friend class KeychainDbCommon;
159public:
160	KeychainDatabase(const DLDbIdentifier &id, const DBParameters &params, Process &proc,
161        const AccessCredentials *cred, const AclEntryPrototype *owner);
162	KeychainDatabase(const DLDbIdentifier &id, const DbBlob *blob, Process &proc,
163        const AccessCredentials *cred);
164
165	// keychain synchronization recode to a specfic blob:
166	KeychainDatabase(KeychainDatabase &src, Process &proc, DbHandle dbToClone);
167	virtual ~KeychainDatabase();
168
169	KeychainDbCommon &common() const;
170	const char *dbName() const;
171	bool transient() const;
172
173    KeychainDbGlobal &global() const { return common().global(); }
174
175public:
176	static const int maxUnlockTryCount = 3;
177
178public:
179    const DbIdentifier &identifier() const { return common().identifier(); }
180
181public:
182	// encoding/decoding databases
183	DbBlob *blob();
184
185    void authenticate(CSSM_DB_ACCESS_TYPE mode, const AccessCredentials *cred);
186    void changePassphrase(const AccessCredentials *cred);
187	RefPointer<Key> extractMasterKey(Database &db, const AccessCredentials *cred,
188		const AclEntryPrototype *owner, uint32 usage, uint32 attrs);
189    void commitSecretsForSync(KeychainDatabase &cloneDb);
190
191	// lock/unlock processing
192	void lockDb();											// unconditional lock
193	void unlockDb();										// full-feature unlock
194	void unlockDb(const CssmData &passphrase);				// unlock with passphrase
195
196    void stashDbCheck();                                    // check AppleKeyStore for master key
197    void stashDb();                                         // stash master key in AppleKeyStore
198
199	bool decode();											// unlock given established master key
200	bool decode(const CssmData &passphrase);				// set master key from PP, try unlock
201
202	bool validatePassphrase(const CssmData &passphrase) const; // nonthrowing validation
203	bool isLocked()			{ return common().isLocked(); }	// lock status
204    void notify(NotificationEvent event) { return common().notify(event); }
205    void activity() const	{ common().activity(); }		// reset timeout clock
206
207	// encoding/decoding keys
208    void decodeKey(KeyBlob *blob, CssmKey &key, void * &pubAcl, void * &privAcl);
209	KeyBlob *encodeKey(const CssmKey &key, const CssmData &pubAcl, const CssmData &privAcl);
210	KeyBlob *recodeKey(KeychainKey &oldKey);
211    bool validBlob() const	{ return mBlob && version == common().version; }
212
213	// manage database parameters
214	void setParameters(const DBParameters &params);
215	void getParameters(DBParameters &params);
216
217	// where's my (database) ACL?
218	SecurityServerAcl &acl();
219
220	AclKind aclKind() const;
221	Database *relatedDatabase();
222
223    // ACL state management hooks
224	void instantiateAcl();
225	void changedAcl();
226
227	// miscellaneous utilities
228	static void validateBlob(const DbBlob *blob);
229
230    // debugging
231    IFDUMP(void dumpNode());
232
233protected:
234	RefPointer<Key> makeKey(const CssmKey &newKey, uint32 moreAttributes, const AclEntryPrototype *owner);
235	RefPointer<Key> makeKey(Database &db, const CssmKey &newKey, uint32 moreAttributes, const AclEntryPrototype *owner);
236
237	void makeUnlocked();							// interior version of unlock()
238	void makeUnlocked(const AccessCredentials *cred); // like () with explicit cred
239	void makeUnlocked(const CssmData &passphrase);	// interior version of unlock(CssmData)
240
241	void establishOldSecrets(const AccessCredentials *creds);
242	void establishNewSecrets(const AccessCredentials *creds, SecurityAgent::Reason reason);
243
244	bool interactiveUnlock();
245
246	CssmClient::Key keyFromCreds(const TypedList &sample, unsigned int requiredLength);
247
248	void encode();									// (re)generate mBlob if needed
249
250private:
251	// all following data is locked by the common lock
252    bool mValidData;				// valid ACL and params (blob decoded)
253    CssmAutoData mSecret;
254    bool mSaveSecret;
255
256    uint32 version;					// version stamp for blob validity
257    DbBlob *mBlob;					// database blob (encoded)
258
259    AccessCredentials *mCred;		// local access credentials (always valid)
260
261	RefPointer<KeychainDatabase> mRecodingSource;	// keychain synchronization ONLY; should not require accessors
262};
263
264#endif //_H_KCDATABASE
265