1/*
2 * Copyright (c) 2000-2009,2012-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//
26// kcdatabase - software database container implementation.
27//
28// General implementation notes:
29// This leverages LocalDatabase/LocalKey for cryptography, and adds the
30//  storage coder/decoder logic that implements "keychain" databases in their
31//  intricately choreographed dance between securityd and the AppleCSPDL.
32// As always, Database objects are lifetime-bound to their Process referent;
33//  they can also be destroyed explicitly with a client release call.
34// DbCommons are reference-held by their Databases, with one extra special
35//  reference (from the Session) introduced when the database unlocks, and
36//  removed when it locks again. That way, an unused DbCommon dies when it
37//  is locked or when the Session dies, whichever happens earlier.
38// There is (as yet) no global-scope Database object for Keychain databases.
39//
40#include "kcdatabase.h"
41#include "agentquery.h"
42#include "kckey.h"
43#include "server.h"
44#include "session.h"
45#include "notifications.h"
46#include <vector>           // @@@  4003540 workaround
47#include <security_agent_client/agentclient.h>
48#include <security_cdsa_utilities/acl_any.h>	// for default owner ACLs
49#include <security_cdsa_utilities/cssmendian.h>
50#include <security_cdsa_client/wrapkey.h>
51#include <security_cdsa_client/genkey.h>
52#include <security_cdsa_client/signclient.h>
53#include <security_cdsa_client/cryptoclient.h>
54#include <security_cdsa_client/macclient.h>
55#include <securityd_client/dictionary.h>
56#include <security_utilities/endian.h>
57#include "securityd_service/securityd_service/securityd_service_client.h"
58#include <AssertMacros.h>
59#include <syslog.h>
60
61void unflattenKey(const CssmData &flatKey, CssmKey &rawKey);	//>> make static method on KeychainDatabase
62
63static int
64unlock_keybag(KeychainDbCommon & dbCommon, const void * secret, int secret_len)
65{
66    int rc = -1;
67
68    if (!dbCommon.isLoginKeychain()) return 0;
69
70    service_context_t context = dbCommon.session().get_current_service_context();
71
72    // try to unlock first if not found then load/create or unlock
73    // loading should happen when the kb common object is created
74    // if it doesn't exist yet then the unlock will fail and we'll create everything
75    rc = service_client_kb_unlock(&context, secret, secret_len);
76    if (rc == KB_BagNotLoaded) {
77        if (service_client_kb_load(&context) == KB_BagNotFound) {
78            rc = service_client_kb_create(&context, secret, secret_len);
79        } else {
80            rc = service_client_kb_unlock(&context, secret, secret_len);
81        }
82    }
83
84    if (rc != 0) { // if we just upgraded make sure we swap the encryption key to the password
85        if (!dbCommon.session().keybagGetState(session_keybag_check_master_key)) {
86            CssmAutoData encKey(Allocator::standard(Allocator::sensitive));
87            dbCommon.get_encryption_key(encKey);
88            if ((rc = service_client_kb_unlock(&context, encKey.data(), (int)encKey.length())) == 0) {
89                rc = service_client_kb_change_secret(&context, encKey.data(), (int)encKey.length(), secret, secret_len);
90            }
91
92            if (rc != 0) { // if a login.keychain password exists but doesnt on the keybag update it
93                bool no_pin = false;
94                if ((secret_len > 0) && service_client_kb_is_locked(&context, NULL, &no_pin) == 0) {
95                    if (no_pin) {
96                        syslog(LOG_ERR, "Updating iCloud keychain passphrase for uid %d", dbCommon.session().originatorUid());
97                        service_client_kb_change_secret(&context, NULL, 0, secret, secret_len);
98                    }
99                }
100            }
101        } // session_keybag_check_master_key
102    }
103
104    if (rc == 0) {
105        dbCommon.session().keybagSetState(session_keybag_unlocked|session_keybag_loaded|session_keybag_check_master_key);
106    } else {
107        syslog(LOG_ERR, "Failed to unlock iCloud keychain for uid %d", dbCommon.session().originatorUid());
108    }
109
110    return rc;
111}
112
113static void
114change_secret_on_keybag(KeychainDbCommon & dbCommon, const void * secret, int secret_len, const void * new_secret, int new_secret_len)
115{
116    if (!dbCommon.isLoginKeychain()) return;
117
118    service_context_t context = dbCommon.session().get_current_service_context();
119
120    // if a login.keychain doesn't exist yet it comes into securityd as a create then change_secret
121    // we need to create the keybag in this case if it doesn't exist
122    if (service_client_kb_change_secret(&context, secret, secret_len, new_secret, new_secret_len) == KB_BagNotLoaded) {
123        if (service_client_kb_load(&context) == KB_BagNotFound) {
124            service_client_kb_create(&context, new_secret, new_secret_len);
125        }
126    }
127}
128
129//
130// Create a Database object from initial parameters (create operation)
131//
132KeychainDatabase::KeychainDatabase(const DLDbIdentifier &id, const DBParameters &params, Process &proc,
133            const AccessCredentials *cred, const AclEntryPrototype *owner)
134    : LocalDatabase(proc), mValidData(false), mSecret(Allocator::standard(Allocator::sensitive)), mSaveSecret(false), version(0), mBlob(NULL)
135{
136    // save a copy of the credentials for later access control
137    mCred = DataWalkers::copy(cred, Allocator::standard());
138
139    // create a new random signature to complete the DLDbIdentifier
140    DbBlob::Signature newSig;
141    Server::active().random(newSig.bytes);
142    DbIdentifier ident(id, newSig);
143
144    // create common block and initialize
145	RefPointer<KeychainDbCommon> newCommon = new KeychainDbCommon(proc.session(), ident);
146	StLock<Mutex> _(*newCommon);
147	parent(*newCommon);
148	// new common is now visible (in ident-map) but we hold its lock
149
150	// establish the new master secret
151	establishNewSecrets(cred, SecurityAgent::newDatabase);
152
153	// set initial database parameters
154	common().mParams = params;
155
156	// the common is "unlocked" now
157	common().makeNewSecrets();
158
159	// establish initial ACL
160	if (owner)
161		acl().cssmSetInitial(*owner);
162	else
163		acl().cssmSetInitial(new AnyAclSubject());
164    mValidData = true;
165
166    // for now, create the blob immediately
167    encode();
168
169	proc.addReference(*this);
170
171	// this new keychain is unlocked; make it so
172	activity();
173
174	SECURITYD_KEYCHAIN_CREATE(&common(), (char*)this->dbName(), this);
175}
176
177
178//
179// Create a Database object from a database blob (decoding)
180//
181KeychainDatabase::KeychainDatabase(const DLDbIdentifier &id, const DbBlob *blob, Process &proc,
182    const AccessCredentials *cred)
183	: LocalDatabase(proc), mValidData(false), mSecret(Allocator::standard(Allocator::sensitive)), mSaveSecret(false), version(0), mBlob(NULL)
184{
185	validateBlob(blob);
186
187    // save a copy of the credentials for later access control
188    mCred = DataWalkers::copy(cred, Allocator::standard());
189    mBlob = blob->copy();
190
191    // check to see if we already know about this database
192    DbIdentifier ident(id, blob->randomSignature);
193	Session &session = process().session();
194	if (RefPointer<KeychainDbCommon> dbcom =
195			session.findFirst<KeychainDbCommon, const DbIdentifier &>(&KeychainDbCommon::identifier, ident)) {
196		parent(*dbcom);
197		//@@@ arbitrate sequence number here, perhaps update common().mParams
198		SECURITYD_KEYCHAIN_JOIN(&common(), (char*)this->dbName(), this);
199	} else {
200		// DbCommon not present; make a new one
201		parent(*new KeychainDbCommon(proc.session(), ident));
202		common().mParams = blob->params;
203		SECURITYD_KEYCHAIN_MAKE(&common(), (char*)this->dbName(), this);
204		// this DbCommon is locked; no timer or reference setting
205	}
206	proc.addReference(*this);
207}
208
209
210// recode/clone:
211//
212// Special-purpose constructor for keychain synchronization.  Copies an
213// existing keychain but uses the operational keys from secretsBlob.  The
214// new KeychainDatabase will silently replace the existing KeychainDatabase
215// as soon as the client declares that re-encoding of all keychain items is
216// finished.  This is a little perilous since it allows a client to dictate
217// securityd state, but we try to ensure that only the client that started
218// the re-encoding can declare it done.
219//
220KeychainDatabase::KeychainDatabase(KeychainDatabase &src, Process &proc, DbHandle dbToClone)
221	: LocalDatabase(proc), mValidData(false), mSecret(Allocator::standard(Allocator::sensitive)), mSaveSecret(false), version(0), mBlob(NULL)
222{
223	mCred = DataWalkers::copy(src.mCred, Allocator::standard());
224
225	// Give this KeychainDatabase a temporary name
226	std::string newDbName = std::string("////") + std::string(src.identifier().dbName());
227	DLDbIdentifier newDLDbIdent(src.identifier().dlDbIdentifier().ssuid(), newDbName.c_str(), src.identifier().dlDbIdentifier().dbLocation());
228	DbIdentifier ident(newDLDbIdent, src.identifier());
229
230    // create common block and initialize
231	RefPointer<KeychainDbCommon> newCommon = new KeychainDbCommon(proc.session(), ident);
232	StLock<Mutex> _(*newCommon);
233	parent(*newCommon);
234
235	// set initial database parameters from the source keychain
236	common().mParams = src.common().mParams;
237
238	// establish the source keychain's master secret as ours
239	// @@@  NB: this is a v. 0.1 assumption.  We *should* trigger new UI
240	//      that offers the user the option of using the existing password
241	//      or choosing a new one.  That would require a new
242	//      SecurityAgentQuery type, new UI, and--possibly--modifications to
243	//      ensure that the new password is available here to generate the
244	//      new master secret.
245	src.unlockDb();		// precaution for masterKey()
246	common().setup(src.blob(), src.common().masterKey());
247
248    // import the operational secrets
249	RefPointer<KeychainDatabase> srcKC = Server::keychain(dbToClone);
250	common().importSecrets(srcKC->common());
251
252	// import source keychain's ACL
253	CssmData pubAcl, privAcl;
254	src.acl().exportBlob(pubAcl, privAcl);
255	importBlob(pubAcl.data(), privAcl.data());
256	src.acl().allocator.free(pubAcl);
257	src.acl().allocator.free(privAcl);
258
259	// indicate that this keychain should be allowed to do some otherwise
260	// risky things required for copying, like re-encoding keys
261	mRecodingSource = &src;
262
263	common().setUnlocked();
264	mValidData = true;
265
266    encode();
267
268	proc.addReference(*this);
269	secdebug("SSdb", "database %s(%p) created as copy, common at %p",
270			 common().dbName(), this, &common());
271}
272
273//
274// Destroy a Database
275//
276KeychainDatabase::~KeychainDatabase()
277{
278    secdebug("KCdb", "deleting database %s(%p) common %p",
279        common().dbName(), this, &common());
280    Allocator::standard().free(mCred);
281	Allocator::standard().free(mBlob);
282}
283
284
285//
286// Basic Database virtual implementations
287//
288KeychainDbCommon &KeychainDatabase::common() const
289{
290	return parent<KeychainDbCommon>();
291}
292
293const char *KeychainDatabase::dbName() const
294{
295	return common().dbName();
296}
297
298bool KeychainDatabase::transient() const
299{
300	return false;	// has permanent store
301}
302
303AclKind KeychainDatabase::aclKind() const
304{
305	return dbAcl;
306}
307
308Database *KeychainDatabase::relatedDatabase()
309{
310	return this;
311}
312
313
314static inline KeychainKey &myKey(Key *key)
315{
316	return *safe_cast<KeychainKey *>(key);
317}
318
319
320//
321// (Re-)Authenticate the database. This changes the stored credentials.
322//
323void KeychainDatabase::authenticate(CSSM_DB_ACCESS_TYPE mode,
324	const AccessCredentials *cred)
325{
326	StLock<Mutex> _(common());
327
328	// the (Apple specific) RESET bit means "lock the database now"
329	switch (mode) {
330	case CSSM_DB_ACCESS_RESET:
331		secdebug("KCdb", "%p ACCESS_RESET triggers keychain lock", this);
332		common().lockDb();
333		break;
334	default:
335		//  store the new credentials for future use
336		secdebug("KCdb", "%p authenticate stores new database credentials", this);
337		AccessCredentials *newCred = DataWalkers::copy(cred, Allocator::standard());
338		Allocator::standard().free(mCred);
339		mCred = newCred;
340	}
341}
342
343
344//
345// Make a new KeychainKey.
346// If PERMANENT is off, make a temporary key instead.
347// The db argument allows you to create for another KeychainDatabase (only);
348// it defaults to ourselves.
349//
350RefPointer<Key> KeychainDatabase::makeKey(Database &db, const CssmKey &newKey,
351	uint32 moreAttributes, const AclEntryPrototype *owner)
352{
353
354	if (moreAttributes & CSSM_KEYATTR_PERMANENT)
355		return new KeychainKey(db, newKey, moreAttributes, owner);
356	else
357		return process().makeTemporaryKey(newKey, moreAttributes, owner);
358}
359
360RefPointer<Key> KeychainDatabase::makeKey(const CssmKey &newKey,
361	uint32 moreAttributes, const AclEntryPrototype *owner)
362{
363	return makeKey(*this, newKey, moreAttributes, owner);
364}
365
366
367//
368// Return the database blob, recalculating it as needed.
369//
370DbBlob *KeychainDatabase::blob()
371{
372	StLock<Mutex> _(common());
373    if (!validBlob()) {
374        makeUnlocked();			// unlock to get master secret
375		encode();				// (re)encode blob if needed
376    }
377    activity();					// reset timeout
378	assert(validBlob());		// better have a valid blob now...
379    return mBlob;
380}
381
382
383//
384// Encode the current database as a blob.
385// Note that this returns memory we own and keep.
386// Caller must hold common lock.
387//
388void KeychainDatabase::encode()
389{
390	DbBlob *blob = common().encode(*this);
391	Allocator::standard().free(mBlob);
392	mBlob = blob;
393	version = common().version;
394	secdebug("KCdb", "encoded database %p common %p(%s) version %u params=(%u,%u)",
395		this, &common(), dbName(), version,
396		common().mParams.idleTimeout, common().mParams.lockOnSleep);
397}
398
399
400//
401// Change the passphrase on a database
402//
403void KeychainDatabase::changePassphrase(const AccessCredentials *cred)
404{
405	// get and hold the common lock (don't let other threads break in here)
406	StLock<Mutex> _(common());
407
408	// establish OLD secret - i.e. unlock the database
409	//@@@ do we want to leave the final lock state alone?
410    if (common().isLoginKeychain()) mSaveSecret = true;
411	makeUnlocked(cred);
412
413    // establish NEW secret
414	establishNewSecrets(cred, SecurityAgent::changePassphrase);
415    if (mSecret) { mSecret.reset(); }
416    mSaveSecret = false;
417	common().invalidateBlob();	// blob state changed
418	secdebug("KCdb", "Database %s(%p) master secret changed", common().dbName(), this);
419	encode();			// force rebuild of local blob
420
421	// send out a notification
422	notify(kNotificationEventPassphraseChanged);
423
424    // I guess this counts as an activity
425    activity();
426}
427
428//
429// Second stage of keychain synchronization: overwrite the original keychain's
430// (this KeychainDatabase's) operational secrets
431//
432void KeychainDatabase::commitSecretsForSync(KeychainDatabase &cloneDb)
433{
434    StLock<Mutex> _(common());
435
436	// try to detect spoofing
437	if (cloneDb.mRecodingSource != this)
438        CssmError::throwMe(CSSM_ERRCODE_INVALID_DB_HANDLE);
439
440    // in case we autolocked since starting the sync
441    makeUnlocked(); // call this because we already own the lock
442	cloneDb.unlockDb(); // we may not own the lock here, so calling unlockDb will lock the cloneDb's common lock
443
444    // Decode all keys whose handles refer to this on-disk keychain so that
445    // if the holding client commits the key back to disk, it's encoded with
446    // the new operational secrets.  The recoding client *must* hold a write
447    // lock for the on-disk keychain from the moment it starts recoding key
448    // items until after this call.
449    //
450	// @@@  This specific implementation is a workaround for 4003540.
451	std::vector<U32HandleObject::Handle> handleList;
452	U32HandleObject::findAllRefs<KeychainKey>(handleList);
453    size_t count = handleList.size();
454	if (count > 0) {
455        for (unsigned int n = 0; n < count; ++n) {
456            RefPointer<KeychainKey> kckey =
457                U32HandleObject::findRefAndLock<KeychainKey>(handleList[n], CSSMERR_CSP_INVALID_KEY_REFERENCE);
458            StLock<Mutex> _(*kckey/*, true*/);
459            if (kckey->database().global().identifier() == identifier()) {
460                kckey->key();               // force decode
461                kckey->invalidateBlob();
462				secdebug("kcrecode", "changed extant key %p (proc %d)",
463						 &*kckey, kckey->process().pid());
464            }
465        }
466	}
467
468    // it is now safe to replace the old op secrets
469    common().importSecrets(cloneDb.common());
470	common().invalidateBlob();
471}
472
473
474//
475// Extract the database master key as a proper Key object.
476//
477RefPointer<Key> KeychainDatabase::extractMasterKey(Database &db,
478	const AccessCredentials *cred, const AclEntryPrototype *owner,
479	uint32 usage, uint32 attrs)
480{
481	// get and hold common lock
482	StLock<Mutex> _(common());
483
484	// force lock to require re-validation of credentials
485	lockDb();
486
487	// unlock to establish master secret
488	makeUnlocked();
489
490	// extract the raw cryptographic key
491	CssmClient::WrapKey wrap(Server::csp(), CSSM_ALGID_NONE);
492	CssmKey key;
493	wrap(common().masterKey(), key);
494
495	// make the key object and return it
496	return makeKey(db, key, attrs & LocalKey::managedAttributes, owner);
497}
498
499
500//
501// Unlock this database (if needed) by obtaining the master secret in some
502// suitable way and then proceeding to unlock with it.
503// Does absolutely nothing if the database is already unlocked.
504// The makeUnlocked forms are identical except the assume the caller already
505// holds the common lock.
506//
507void KeychainDatabase::unlockDb()
508{
509	StLock<Mutex> _(common());
510	makeUnlocked();
511}
512
513void KeychainDatabase::makeUnlocked()
514{
515	return makeUnlocked(mCred);
516}
517
518void KeychainDatabase::makeUnlocked(const AccessCredentials *cred)
519{
520    if (isLocked()) {
521		secdebug("KCdb", "%p(%p) unlocking for makeUnlocked()", this, &common());
522        assert(mBlob || (mValidData && common().hasMaster()));
523		establishOldSecrets(cred);
524		common().setUnlocked(); // mark unlocked
525        if (common().isLoginKeychain()) {
526            CssmKey master = common().masterKey();
527            CssmKey rawMaster;
528            CssmClient::WrapKey wrap(Server::csp(), CSSM_ALGID_NONE);
529            wrap(master, rawMaster);
530
531            service_context_t context = common().session().get_current_service_context();
532            service_client_stash_load_key(&context, rawMaster.keyData(), (int)rawMaster.length());
533        }
534	} else if (common().isLoginKeychain()) {
535        bool locked = false;
536        service_context_t context = common().session().get_current_service_context();
537        if ((service_client_kb_is_locked(&context, &locked, NULL) == 0) && locked) {
538            StSyncLock<Mutex, Mutex> uisync(common().uiLock(), common());
539            QueryKeybagPassphrase keybagQuery(common().session(), 3);
540            keybagQuery.inferHints(Server::process());
541            if (keybagQuery.query() != SecurityAgent::noReason) {
542                syslog(LOG_NOTICE, "failed to unlock iCloud keychain");
543            }
544        }
545    }
546	if (!mValidData) {	// need to decode to get our ACLs, master secret available
547		secdebug("KCdb", "%p(%p) is unlocked; decoding for makeUnlocked()", this, &common());
548		if (!decode())
549			CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
550	}
551	assert(!isLocked());
552	assert(mValidData);
553}
554
555//
556// Invoke the securityd_service to retrieve the keychain master
557// key from the AppleFDEKeyStore.
558//
559void KeychainDatabase::stashDbCheck()
560{
561    CssmAutoData masterKey(Allocator::standard(Allocator::sensitive));
562    CssmAutoData encKey(Allocator::standard(Allocator::sensitive));
563
564    // Fetch the key
565    int rc = 0;
566    void * stash_key = NULL;
567    int stash_key_len = 0;
568    service_context_t context = common().session().get_current_service_context();
569    rc = service_client_stash_get_key(&context, &stash_key, &stash_key_len);
570    if (rc == 0) {
571        if (stash_key) {
572            masterKey.copy(CssmData((void *)stash_key,stash_key_len));
573            memset(stash_key, 0, stash_key_len);
574            free(stash_key);
575        }
576    } else {
577        CssmError::throwMe(rc);
578    }
579
580    {
581        StLock<Mutex> _(common());
582
583        // Now establish it as the keychain master key
584        CssmClient::Key key(Server::csp(), masterKey.get());
585        CssmKey::Header &hdr = key.header();
586        hdr.keyClass(CSSM_KEYCLASS_SESSION_KEY);
587        hdr.algorithm(CSSM_ALGID_3DES_3KEY_EDE);
588        hdr.usage(CSSM_KEYUSE_ANY);
589        hdr.blobType(CSSM_KEYBLOB_RAW);
590        hdr.blobFormat(CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING);
591        common().setup(mBlob, key);
592
593        if (!decode())
594            CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
595
596        common().get_encryption_key(encKey);
597    }
598
599    // when upgrading from pre-10.9 create a keybag if it doesn't exist with the encryption key
600    // only do this after we have verified the master key unlocks the login.keychain
601    if (service_client_kb_load(&context) == KB_BagNotFound) {
602        service_client_kb_create(&context, encKey.data(), (int)encKey.length());
603    }
604}
605
606//
607// Get the keychain master key and invoke the securityd_service
608// to stash it in the AppleFDEKeyStore ready for commit to the
609// NVRAM blob.
610//
611void KeychainDatabase::stashDb()
612{
613    CssmAutoData data(Allocator::standard(Allocator::sensitive));
614
615    {
616        StLock<Mutex> _(common());
617
618        if (!common().isValid()) {
619            CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
620        }
621
622        CssmKey key = common().masterKey();
623        data.copy(key.keyData());
624    }
625
626    service_context_t context = common().session().get_current_service_context();
627    int rc = service_client_stash_set_key(&context, data.data(), (int)data.length());
628    if (rc != 0) CssmError::throwMe(rc);
629}
630
631//
632// The following unlock given an explicit passphrase, rather than using
633// (special cred sample based) default procedures.
634//
635void KeychainDatabase::unlockDb(const CssmData &passphrase)
636{
637	StLock<Mutex> _(common());
638	makeUnlocked(passphrase);
639}
640
641void KeychainDatabase::makeUnlocked(const CssmData &passphrase)
642{
643	if (isLocked()) {
644		if (decode(passphrase))
645			return;
646		else
647			CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
648	} else if (!mValidData)	{	// need to decode to get our ACLs, passphrase available
649		if (!decode())
650			CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
651	}
652
653    if (common().isLoginKeychain()) {
654        bool locked = false;
655        service_context_t context = common().session().get_current_service_context();
656        if (!common().session().keybagGetState(session_keybag_check_master_key) || ((service_client_kb_is_locked(&context, &locked, NULL) == 0) && locked)) {
657            unlock_keybag(common(), passphrase.data(), (int)passphrase.length());
658        }
659    }
660
661	assert(!isLocked());
662	assert(mValidData);
663}
664
665
666//
667// Nonthrowing passphrase-based unlock. This returns false if unlock failed.
668// Note that this requires an explicitly given passphrase.
669// Caller must hold common lock.
670//
671bool KeychainDatabase::decode(const CssmData &passphrase)
672{
673	assert(mBlob);
674	common().setup(mBlob, passphrase);
675	bool success = decode();
676    if (success && common().isLoginKeychain()) {
677        unlock_keybag(common(), passphrase.data(), (int)passphrase.length());
678    }
679    return success;
680}
681
682
683//
684// Given the established master secret, decode the working keys and other
685// functional secrets for this database. Return false (do NOT throw) if
686// the decode fails. Call this in low(er) level code once you established
687// the master key.
688//
689bool KeychainDatabase::decode()
690{
691	assert(mBlob);
692	assert(common().hasMaster());
693	void *privateAclBlob;
694	if (common().unlockDb(mBlob, &privateAclBlob)) {
695		if (!mValidData) {
696			acl().importBlob(mBlob->publicAclBlob(), privateAclBlob);
697			mValidData = true;
698		}
699		Allocator::standard().free(privateAclBlob);
700		return true;
701	}
702	secdebug("KCdb", "%p decode failed", this);
703	return false;
704}
705
706
707//
708// Given an AccessCredentials for this database, wring out the existing primary
709// database secret by whatever means necessary.
710// On entry, caller must hold the database common lock. It will be held
711// throughout except when user interaction is required. User interaction
712// requires relinquishing the database common lock and taking the UI lock. On
713// return from user interaction, the UI lock is relinquished and the database
714// common lock must be reacquired. At no time may the caller hold both locks.
715// On exit, the crypto core has its master secret. If things go wrong,
716// we will throw a suitable exception. Note that encountering any malformed
717// credential sample will throw, but this is not guaranteed -- don't assume
718// that NOT throwing means creds is entirely well-formed (it may just be good
719// enough to work THIS time).
720//
721// How this works:
722// Walk through the creds. Fish out those credentials (in order) that
723// are for unlock processing (they have no ACL subject correspondents),
724// and (try to) obey each in turn, until one produces a valid secret
725// or you run out. If no special samples are found at all, interpret that as
726// "use the system global default," which happens to be hard-coded right here.
727//
728void KeychainDatabase::establishOldSecrets(const AccessCredentials *creds)
729{
730	bool forSystem = this->belongsToSystem();	// this keychain belongs to the system security domain
731
732	// attempt system-keychain unlock
733	if (forSystem) {
734		SystemKeychainKey systemKeychain(kSystemUnlockFile);
735		if (systemKeychain.matches(mBlob->randomSignature)) {
736			secdebug("KCdb", "%p attempting system unlock", this);
737			common().setup(mBlob, CssmClient::Key(Server::csp(), systemKeychain.key(), true));
738			if (decode())
739				return;
740		}
741	}
742
743	list<CssmSample> samples;
744	if (creds && creds->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK, samples)) {
745		for (list<CssmSample>::iterator it = samples.begin(); it != samples.end(); it++) {
746			TypedList &sample = *it;
747			sample.checkProper();
748			switch (sample.type()) {
749			// interactively prompt the user - no additional data
750			case CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT:
751				if (!forSystem) {
752					if (interactiveUnlock())
753						return;
754				}
755                break;
756			// try to use an explicitly given passphrase - Data:passphrase
757			case CSSM_SAMPLE_TYPE_PASSWORD:
758				if (sample.length() != 2)
759					CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE);
760				secdebug("KCdb", "%p attempting passphrase unlock", this);
761				if (decode(sample[1]))
762					return;
763				break;
764			// try to open with a given master key - Data:CSP or KeyHandle, Data:CssmKey
765			case CSSM_SAMPLE_TYPE_SYMMETRIC_KEY:
766			case CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY:
767				assert(mBlob);
768				secdebug("KCdb", "%p attempting explicit key unlock", this);
769				common().setup(mBlob, keyFromCreds(sample, 4));
770                if (decode()) {
771					return;
772                }
773				break;
774			// explicitly defeat the default action but don't try anything in particular
775			case CSSM_WORDID_CANCELED:
776				secdebug("KCdb", "%p defeat default action", this);
777				break;
778			default:
779				// Unknown sub-sample for unlocking.
780				// If we wanted to be fascist, we could now do
781				//  CssmError::throwMe(CSSM_ERRCODE_SAMPLE_VALUE_NOT_SUPPORTED);
782				// But instead we try to be tolerant and continue on.
783				// This DOES however count as an explicit attempt at specifying unlock,
784				// so we will no longer try the default case below...
785				secdebug("KCdb", "%p unknown sub-sample unlock (%d) ignored", this, sample.type());
786				break;
787			}
788		}
789	} else {
790		// default action
791		assert(mBlob);
792
793		if (!forSystem) {
794			if (interactiveUnlock())
795				return;
796		}
797	}
798
799	// out of options - no secret obtained
800	CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
801}
802
803bool KeychainDatabase::interactiveUnlock()
804{
805	secdebug("KCdb", "%p attempting interactive unlock", this);
806	SecurityAgent::Reason reason = SecurityAgent::noReason;
807    QueryUnlock query(*this);
808	// take UI interlock and release DbCommon lock (to avoid deadlocks)
809	StSyncLock<Mutex, Mutex> uisync(common().uiLock(), common());
810
811	// now that we have the UI lock, interact unless another thread unlocked us first
812	if (isLocked()) {
813		query.inferHints(Server::process());
814        reason = query();
815        if (mSaveSecret && reason == SecurityAgent::noReason) {
816            query.retrievePassword(mSecret);
817        }
818        query.disconnect();
819	} else {
820		secdebug("KCdb", "%p was unlocked during uiLock delay", this);
821	}
822
823    if (common().isLoginKeychain()) {
824        bool locked = false;
825        service_context_t context = common().session().get_current_service_context();
826        if ((service_client_kb_is_locked(&context, &locked, NULL) == 0) && locked) {
827            QueryKeybagNewPassphrase keybagQuery(common().session());
828            keybagQuery.inferHints(Server::process());
829            CssmAutoData pass(Allocator::standard(Allocator::sensitive));
830            CssmAutoData oldPass(Allocator::standard(Allocator::sensitive));
831            SecurityAgent::Reason queryReason = keybagQuery.query(oldPass, pass);
832            if (queryReason == SecurityAgent::noReason) {
833                service_client_kb_change_secret(&context, oldPass.data(), (int)oldPass.length(), pass.data(), (int)pass.length());
834            } else if (queryReason == SecurityAgent::resettingPassword) {
835                query.retrievePassword(pass);
836                service_client_kb_reset(&context, pass.data(), (int)pass.length());
837            }
838
839        }
840    }
841
842    return reason == SecurityAgent::noReason;
843}
844
845
846//
847// Same thing, but obtain a new secret somehow and set it into the common.
848//
849void KeychainDatabase::establishNewSecrets(const AccessCredentials *creds, SecurityAgent::Reason reason)
850{
851	list<CssmSample> samples;
852	if (creds && creds->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK, samples)) {
853		for (list<CssmSample>::iterator it = samples.begin(); it != samples.end(); it++) {
854			TypedList &sample = *it;
855			sample.checkProper();
856			switch (sample.type()) {
857			// interactively prompt the user
858			case CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT:
859                {
860				secdebug("KCdb", "%p specified interactive passphrase", this);
861				QueryNewPassphrase query(*this, reason);
862				StSyncLock<Mutex, Mutex> uisync(common().uiLock(), common());
863				query.inferHints(Server::process());
864				CssmAutoData passphrase(Allocator::standard(Allocator::sensitive));
865                CssmAutoData oldPassphrase(Allocator::standard(Allocator::sensitive));
866				if (query(oldPassphrase, passphrase) == SecurityAgent::noReason) {
867					common().setup(NULL, passphrase);
868                    change_secret_on_keybag(common(), oldPassphrase.data(), (int)oldPassphrase.length(), passphrase.data(), (int)passphrase.length());
869					return;
870				}
871                }
872				break;
873			// try to use an explicitly given passphrase
874			case CSSM_SAMPLE_TYPE_PASSWORD:
875				{
876                    secdebug("KCdb", "%p specified explicit passphrase", this);
877                    if (sample.length() != 2)
878                        CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE);
879                    common().setup(NULL, sample[1]);
880                    if (common().isLoginKeychain()) {
881                        CssmAutoData oldPassphrase(Allocator::standard(Allocator::sensitive));
882                        list<CssmSample> oldSamples;
883                        creds->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK, oldSamples);
884                        for (list<CssmSample>::iterator oit = oldSamples.begin(); oit != oldSamples.end(); oit++) {
885                            TypedList &tmpList = *oit;
886                            tmpList.checkProper();
887                            if (tmpList.type() == CSSM_SAMPLE_TYPE_PASSWORD) {
888                                if (tmpList.length() == 2) {
889                                    oldPassphrase = tmpList[1].data();
890                                }
891                            }
892                        }
893                        if (!oldPassphrase.length() && mSecret && mSecret.length()) {
894                            oldPassphrase = mSecret;
895                        }
896                        change_secret_on_keybag(common(), oldPassphrase.data(), (int)oldPassphrase.length(), sample[1].data().data(), (int)sample[1].data().length());
897                    }
898                    return;
899                }
900			// try to open with a given master key
901			case CSSM_WORDID_SYMMETRIC_KEY:
902			case CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY:
903				secdebug("KCdb", "%p specified explicit master key", this);
904				common().setup(NULL, keyFromCreds(sample, 3));
905				return;
906			// explicitly defeat the default action but don't try anything in particular
907			case CSSM_WORDID_CANCELED:
908				secdebug("KCdb", "%p defeat default action", this);
909				break;
910			default:
911				// Unknown sub-sample for acquiring new secret.
912				// If we wanted to be fascist, we could now do
913				//  CssmError::throwMe(CSSM_ERRCODE_SAMPLE_VALUE_NOT_SUPPORTED);
914				// But instead we try to be tolerant and continue on.
915				// This DOES however count as an explicit attempt at specifying unlock,
916				// so we will no longer try the default case below...
917				secdebug("KCdb", "%p unknown sub-sample acquisition (%d) ignored",
918					this, sample.type());
919				break;
920			}
921		}
922	} else {
923		// default action -- interactive (only)
924		QueryNewPassphrase query(*this, reason);
925		StSyncLock<Mutex, Mutex> uisync(common().uiLock(), common());
926        query.inferHints(Server::process());
927		CssmAutoData passphrase(Allocator::standard(Allocator::sensitive));
928        CssmAutoData oldPassphrase(Allocator::standard(Allocator::sensitive));
929		if (query(oldPassphrase, passphrase) == SecurityAgent::noReason) {
930			common().setup(NULL, passphrase);
931            change_secret_on_keybag(common(), oldPassphrase.data(), (int)oldPassphrase.length(), passphrase.data(), (int)passphrase.length());
932			return;
933		}
934	}
935
936	// out of options - no secret obtained
937	CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
938}
939
940
941//
942// Given a (truncated) Database credentials TypedList specifying a master key,
943// locate the key and return a reference to it.
944//
945CssmClient::Key KeychainDatabase::keyFromCreds(const TypedList &sample, unsigned int requiredLength)
946{
947	// decode TypedList structure (sample type; Data:CSPHandle; Data:CSSM_KEY)
948	assert(sample.type() == CSSM_SAMPLE_TYPE_SYMMETRIC_KEY || sample.type() == CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY);
949	if (sample.length() != requiredLength
950		|| sample[1].type() != CSSM_LIST_ELEMENT_DATUM
951		|| sample[2].type() != CSSM_LIST_ELEMENT_DATUM
952		|| (requiredLength == 4 && sample[3].type() != CSSM_LIST_ELEMENT_DATUM))
953			CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE);
954	KeyHandle &handle = *sample[1].data().interpretedAs<KeyHandle>(CSSM_ERRCODE_INVALID_SAMPLE_VALUE);
955    // We used to be able to check the length but supporting multiple client
956    // architectures dishes that (sizeof(CSSM_KEY) varies due to alignment and
957    // field-size differences).  The decoding in the transition layer should
958    // serve as a sufficient garbling check anyway.
959    if (sample[2].data().data() == NULL)
960        CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE);
961    CssmKey &key = *sample[2].data().interpretedAs<CssmKey>();
962
963	if (key.header().cspGuid() == gGuidAppleCSPDL) {
964		// handleOrKey is a SecurityServer KeyHandle; ignore key argument
965		return safer_cast<LocalKey &>(*Server::key(handle));
966	} else
967	if (sample.type() == CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY) {
968		/*
969			Contents (see DefaultCredentials::unlockKey in libsecurity_keychain/defaultcreds.cpp)
970
971			sample[0]	sample type
972			sample[1]	csp handle for master or wrapping key; is really a keyhandle
973			sample[2]	masterKey [not used since securityd cannot interpret; use sample[1] handle instead]
974			sample[3]	UnlockReferralRecord data, in this case the flattened symmetric key
975		*/
976
977		// RefPointer<Key> Server::key(KeyHandle key)
978		KeyHandle keyhandle = *sample[1].data().interpretedAs<KeyHandle>(CSSM_ERRCODE_INVALID_SAMPLE_VALUE);
979		CssmData &flattenedKey = sample[3].data();
980		RefPointer<Key> unwrappingKey = Server::key(keyhandle);
981		Database &db=unwrappingKey->database();
982
983		CssmKey rawWrappedKey;
984		unflattenKey(flattenedKey, rawWrappedKey);
985
986		RefPointer<Key> masterKey;
987		CssmData emptyDescriptiveData;
988		const AccessCredentials *cred = NULL;
989		const AclEntryPrototype *owner = NULL;
990		CSSM_KEYUSE usage = CSSM_KEYUSE_ANY;
991		CSSM_KEYATTR_FLAGS attrs = CSSM_KEYATTR_EXTRACTABLE;	//CSSM_KEYATTR_RETURN_REF |
992
993		// Get default credentials for unwrappingKey (the one on the token)
994		// Copied from Statics::Statics() in libsecurity_keychain/aclclient.cpp
995		// Following KeyItem::getCredentials, one sees that the "operation" parameter
996		// e.g. "CSSM_ACL_AUTHORIZATION_DECRYPT" is ignored
997		Allocator &alloc = Allocator::standard();
998		AutoCredentials promptCred(alloc, 3);// enable interactive prompting
999
1000		// promptCred: a credential permitting user prompt confirmations
1001		// contains:
1002		//  a KEYCHAIN_PROMPT sample, both by itself and in a THRESHOLD
1003		//  a PROMPTED_PASSWORD sample
1004		promptCred.sample(0) = TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT);
1005		promptCred.sample(1) = TypedList(alloc, CSSM_SAMPLE_TYPE_THRESHOLD,
1006			new(alloc) ListElement(TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT)));
1007		promptCred.sample(2) = TypedList(alloc, CSSM_SAMPLE_TYPE_PROMPTED_PASSWORD,
1008			new(alloc) ListElement(alloc, CssmData()));
1009
1010		// This unwrap object is here just to provide a context
1011		CssmClient::UnwrapKey unwrap(Server::csp(), CSSM_ALGID_NONE);	//ok to lie about csp here
1012		unwrap.mode(CSSM_ALGMODE_NONE);
1013		unwrap.padding(CSSM_PADDING_PKCS1);
1014		unwrap.cred(promptCred);
1015		unwrap.add(CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT, uint32(CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7));
1016		Security::Context *tmpContext;
1017		CSSM_CC_HANDLE CCHandle = unwrap.handle();
1018		/*CSSM_RETURN rx = */ CSSM_GetContext (CCHandle, (CSSM_CONTEXT_PTR *)&tmpContext);
1019
1020		// OK, this is skanky but necessary. We overwrite fields in the context struct
1021
1022		tmpContext->ContextType = CSSM_ALGCLASS_ASYMMETRIC;
1023		tmpContext->AlgorithmType = CSSM_ALGID_RSA;
1024
1025		db.unwrapKey(*tmpContext, cred, owner, unwrappingKey, NULL, usage, attrs,
1026			rawWrappedKey, masterKey, emptyDescriptiveData);
1027
1028	    Allocator::standard().free(rawWrappedKey.KeyData.Data);
1029
1030		return safer_cast<LocalKey &>(*masterKey).key();
1031	}
1032	else
1033	{
1034		// not a KeyHandle reference; use key as a raw key
1035		if (key.header().blobType() != CSSM_KEYBLOB_RAW)
1036			CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE);
1037		if (key.header().keyClass() != CSSM_KEYCLASS_SESSION_KEY)
1038			CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
1039		return CssmClient::Key(Server::csp(), key, true);
1040	}
1041}
1042
1043void unflattenKey(const CssmData &flatKey, CssmKey &rawKey)
1044{
1045	// unflatten the raw input key naively: key header then key data
1046	// We also convert it back to host byte order
1047	// A CSSM_KEY is a CSSM_KEYHEADER followed by a CSSM_DATA
1048
1049	// Now copy: header, then key struct, then key data
1050	memcpy(&rawKey.KeyHeader, flatKey.Data, sizeof(CSSM_KEYHEADER));
1051	memcpy(&rawKey.KeyData, flatKey.Data + sizeof(CSSM_KEYHEADER), sizeof(CSSM_DATA));
1052	const uint32 keyDataLength = flatKey.length() - sizeof(CSSM_KEY);
1053	rawKey.KeyData.Data = Allocator::standard().malloc<uint8>(keyDataLength);
1054	rawKey.KeyData.Length = keyDataLength;
1055	memcpy(rawKey.KeyData.Data, flatKey.Data + sizeof(CSSM_KEY), keyDataLength);
1056	Security::n2hi(rawKey.KeyHeader);	// convert it to host byte order
1057}
1058
1059
1060//
1061// Verify a putative database passphrase.
1062// If the database is already unlocked, just check the passphrase.
1063// Otherwise, unlock with that passphrase and report success.
1064// Caller must hold the common lock.
1065//
1066bool KeychainDatabase::validatePassphrase(const CssmData &passphrase) const
1067{
1068	if (common().hasMaster()) {
1069		// verify against known secret
1070		return common().validatePassphrase(passphrase);
1071	} else {
1072		// no master secret - perform "blind" unlock to avoid actual unlock
1073		try {
1074			DatabaseCryptoCore test;
1075			test.setup(mBlob, passphrase);
1076			test.decodeCore(mBlob, NULL);
1077			return true;
1078		} catch (...) {
1079			return false;
1080		}
1081	}
1082}
1083
1084
1085//
1086// Lock this database
1087//
1088void KeychainDatabase::lockDb()
1089{
1090    common().lockDb();
1091}
1092
1093
1094//
1095// Given a Key for this database, encode it into a blob and return it.
1096//
1097KeyBlob *KeychainDatabase::encodeKey(const CssmKey &key, const CssmData &pubAcl, const CssmData &privAcl)
1098{
1099	bool inTheClear = false;
1100	if((key.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY) &&
1101	   !(key.attribute(CSSM_KEYATTR_PUBLIC_KEY_ENCRYPT))) {
1102		inTheClear = true;
1103	}
1104	StLock<Mutex> _(common());
1105	if(!inTheClear)
1106		makeUnlocked();
1107
1108    // tell the cryptocore to form the key blob
1109    return common().encodeKeyCore(key, pubAcl, privAcl, inTheClear);
1110}
1111
1112
1113//
1114// Given a "blobbed" key for this database, decode it into its real
1115// key object and (re)populate its ACL.
1116//
1117void KeychainDatabase::decodeKey(KeyBlob *blob, CssmKey &key, void * &pubAcl, void * &privAcl)
1118{
1119	StLock<Mutex> _(common());
1120
1121	if(!blob->isClearText())
1122		makeUnlocked();							// we need our keys
1123
1124	common().decodeKeyCore(blob, key, pubAcl, privAcl);
1125	// memory protocol: pubAcl points into blob; privAcl was allocated
1126
1127    activity();
1128}
1129
1130//
1131// Given a KeychainKey (that implicitly belongs to another keychain),
1132// return it encoded using this keychain's operational secrets.
1133//
1134KeyBlob *KeychainDatabase::recodeKey(KeychainKey &oldKey)
1135{
1136	if (mRecodingSource != &oldKey.referent<KeychainDatabase>()) {
1137        CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
1138    }
1139	oldKey.instantiateAcl();	// make sure key is decoded
1140	CssmData publicAcl, privateAcl;
1141	oldKey.exportBlob(publicAcl, privateAcl);
1142	// NB: blob's memory belongs to caller, not the common
1143
1144	/*
1145	 * Make sure the new key is in the same cleartext/encrypted state.
1146	 */
1147	bool inTheClear = false;
1148	assert(oldKey.blob());
1149	if(oldKey.blob() && oldKey.blob()->isClearText()) {
1150		/* careful....*/
1151		inTheClear = true;
1152	}
1153	KeyBlob *blob = common().encodeKeyCore(oldKey.cssmKey(), publicAcl, privateAcl, inTheClear);
1154	oldKey.acl().allocator.free(publicAcl);
1155	oldKey.acl().allocator.free(privateAcl);
1156	return blob;
1157}
1158
1159
1160//
1161// Modify database parameters
1162//
1163void KeychainDatabase::setParameters(const DBParameters &params)
1164{
1165	StLock<Mutex> _(common());
1166    makeUnlocked();
1167	common().mParams = params;
1168    common().invalidateBlob();		// invalidate old blobs
1169    activity();				// (also resets the timeout timer)
1170	secdebug("KCdb", "%p common %p(%s) set params=(%u,%u)",
1171		this, &common(), dbName(), params.idleTimeout, params.lockOnSleep);
1172}
1173
1174
1175//
1176// Retrieve database parameters
1177//
1178void KeychainDatabase::getParameters(DBParameters &params)
1179{
1180	StLock<Mutex> _(common());
1181    makeUnlocked();
1182	params = common().mParams;
1183    //activity();		// getting parameters does not reset the idle timer
1184}
1185
1186
1187//
1188// RIGHT NOW, database ACLs are attached to the database.
1189// This will soon move upstairs.
1190//
1191SecurityServerAcl &KeychainDatabase::acl()
1192{
1193	return *this;
1194}
1195
1196
1197//
1198// Intercept ACL change requests and reset blob validity
1199//
1200void KeychainDatabase::instantiateAcl()
1201{
1202	StLock<Mutex> _(common());
1203	makeUnlocked();
1204}
1205
1206void KeychainDatabase::changedAcl()
1207{
1208	StLock<Mutex> _(common());
1209	version = 0;
1210}
1211
1212
1213//
1214// Check an incoming DbBlob for basic viability
1215//
1216void KeychainDatabase::validateBlob(const DbBlob *blob)
1217{
1218    // perform basic validation on the blob
1219	assert(blob);
1220	blob->validate(CSSMERR_APPLEDL_INVALID_DATABASE_BLOB);
1221	switch (blob->version()) {
1222#if defined(COMPAT_OSX_10_0)
1223		case DbBlob::version_MacOS_10_0:
1224			break;
1225#endif
1226		case DbBlob::version_MacOS_10_1:
1227			break;
1228		default:
1229			CssmError::throwMe(CSSMERR_APPLEDL_INCOMPATIBLE_DATABASE_BLOB);
1230	}
1231}
1232
1233
1234//
1235// Debugging support
1236//
1237#if defined(DEBUGDUMP)
1238
1239void KeychainDbCommon::dumpNode()
1240{
1241	PerSession::dumpNode();
1242	uint32 sig; memcpy(&sig, &mIdentifier.signature(), sizeof(sig));
1243	Debug::dump(" %s[%8.8x]", mIdentifier.dbName(), sig);
1244	if (isLocked()) {
1245		Debug::dump(" locked");
1246	} else {
1247		time_t whenTime = time_t(when());
1248		Debug::dump(" unlocked(%24.24s/%.2g)", ctime(&whenTime),
1249			(when() - Time::now()).seconds());
1250	}
1251	Debug::dump(" params=(%u,%u)", mParams.idleTimeout, mParams.lockOnSleep);
1252}
1253
1254void KeychainDatabase::dumpNode()
1255{
1256	PerProcess::dumpNode();
1257	Debug::dump(" %s vers=%u",
1258		mValidData ? " data" : " nodata", version);
1259	if (mBlob) {
1260		uint32 sig; memcpy(&sig, &mBlob->randomSignature, sizeof(sig));
1261		Debug::dump(" blob=%p[%8.8x]", mBlob, sig);
1262	} else {
1263		Debug::dump(" noblob");
1264	}
1265}
1266
1267#endif //DEBUGDUMP
1268
1269
1270//
1271// DbCommon basic features
1272//
1273KeychainDbCommon::KeychainDbCommon(Session &ssn, const DbIdentifier &id)
1274	: LocalDbCommon(ssn), sequence(0), version(1), mIdentifier(id),
1275      mIsLocked(true), mValidParams(false), mLoginKeychain(false)
1276{
1277    // match existing DbGlobal or create a new one
1278	{
1279        Server &server = Server::active();
1280        StLock<Mutex> _(server);
1281        if (KeychainDbGlobal *dbglobal =
1282                server.findFirst<KeychainDbGlobal, const DbIdentifier &>(&KeychainDbGlobal::identifier, identifier())) {
1283            parent(*dbglobal);
1284            secdebug("KCdb", "%p linking to existing DbGlobal %p", this, dbglobal);
1285        } else {
1286            // DbGlobal not present; make a new one
1287            parent(*new KeychainDbGlobal(identifier()));
1288            secdebug("KCdb", "%p linking to new DbGlobal %p", this, &global());
1289        }
1290
1291        // link lifetime to the Session
1292        session().addReference(*this);
1293
1294        if (strcasestr(id.dbName(), "login.keychain") != NULL) {
1295            mLoginKeychain = true;
1296        }
1297    }
1298
1299    if (mLoginKeychain && !session().keybagGetState(session_keybag_loaded)) {
1300        service_context_t context = session().get_current_service_context();
1301        if (service_client_kb_load(&context) == 0) {
1302            session().keybagSetState(session_keybag_loaded);
1303        }
1304    }
1305}
1306
1307KeychainDbCommon::~KeychainDbCommon()
1308{
1309	SECURITYD_KEYCHAIN_RELEASE(this, (char*)this->dbName());
1310
1311	// explicitly unschedule ourselves
1312	Server::active().clearTimer(this);
1313    if (mLoginKeychain) {
1314        session().keybagClearState(session_keybag_unlocked);
1315    }
1316}
1317
1318KeychainDbGlobal &KeychainDbCommon::global() const
1319{
1320	return parent<KeychainDbGlobal>();
1321}
1322
1323
1324void KeychainDbCommon::select()
1325{ this->ref(); }
1326
1327void KeychainDbCommon::unselect()
1328{ this->unref(); }
1329
1330
1331
1332void KeychainDbCommon::makeNewSecrets()
1333{
1334	// we already have a master key (right?)
1335	assert(hasMaster());
1336
1337	// tell crypto core to generate the use keys
1338	DatabaseCryptoCore::generateNewSecrets();
1339
1340	// we're now officially "unlocked"; set the timer
1341	setUnlocked();
1342}
1343
1344
1345//
1346// All unlocking activity ultimately funnels through this method.
1347// This unlocks a DbCommon using the secrets setup in its crypto core
1348// component, and performs all the housekeeping needed to represent
1349// the state change.
1350// Returns true if unlock was successful, false if it failed due to
1351// invalid/insufficient secrets. Throws on other errors.
1352//
1353bool KeychainDbCommon::unlockDb(DbBlob *blob, void **privateAclBlob)
1354{
1355	try {
1356		// Tell the cryptocore to (try to) decode itself. This will fail
1357		// in an astonishing variety of ways if the passphrase is wrong.
1358		assert(hasMaster());
1359		decodeCore(blob, privateAclBlob);
1360		secdebug("KCdb", "%p unlock successful", this);
1361	} catch (...) {
1362		secdebug("KCdb", "%p unlock failed", this);
1363		return false;
1364	}
1365
1366	// get the database parameters only if we haven't got them yet
1367	if (!mValidParams) {
1368		mParams = blob->params;
1369		n2hi(mParams.idleTimeout);
1370		mValidParams = true;	// sticky
1371	}
1372
1373	bool isLocked = mIsLocked;
1374
1375	setUnlocked();		// mark unlocked
1376
1377	if (isLocked) {
1378		// broadcast unlock notification, but only if we were previously locked
1379		notify(kNotificationEventUnlocked);
1380		SECURITYD_KEYCHAIN_UNLOCK(this, (char*)this->dbName());
1381	}
1382    return true;
1383}
1384
1385void KeychainDbCommon::setUnlocked()
1386{
1387	session().addReference(*this);	// active/held
1388	mIsLocked = false;				// mark unlocked
1389	activity();						// set timeout timer
1390}
1391
1392
1393void KeychainDbCommon::lockDb()
1394{
1395    bool lock = false;
1396    {
1397        StLock<Mutex> _(*this);
1398        if (!isLocked()) {
1399            DatabaseCryptoCore::invalidate();
1400            notify(kNotificationEventLocked);
1401            SECURITYD_KEYCHAIN_LOCK(this, (char*)this->dbName());
1402            Server::active().clearTimer(this);
1403
1404            mIsLocked = true;		// mark locked
1405            lock = true;
1406
1407            // this call may destroy us if we have no databases anymore
1408            session().removeReference(*this);
1409        }
1410    }
1411
1412    if (mLoginKeychain && lock) {
1413        service_context_t context = session().get_current_service_context();
1414        service_client_kb_lock(&context);
1415        session().keybagClearState(session_keybag_unlocked);
1416    }
1417}
1418
1419
1420DbBlob *KeychainDbCommon::encode(KeychainDatabase &db)
1421{
1422    assert(!isLocked());	// must have been unlocked by caller
1423
1424    // export database ACL to blob form
1425    CssmData pubAcl, privAcl;
1426    db.acl().exportBlob(pubAcl, privAcl);
1427
1428    // tell the cryptocore to form the blob
1429    DbBlob form;
1430    form.randomSignature = identifier();
1431    form.sequence = sequence;
1432    form.params = mParams;
1433	h2ni(form.params.idleTimeout);
1434
1435	assert(hasMaster());
1436    DbBlob *blob = encodeCore(form, pubAcl, privAcl);
1437
1438    // clean up and go
1439    db.acl().allocator.free(pubAcl);
1440    db.acl().allocator.free(privAcl);
1441	return blob;
1442}
1443
1444
1445//
1446// Perform deferred lock processing for a database.
1447//
1448void KeychainDbCommon::action()
1449{
1450	secdebug("KCdb", "common %s(%p) locked by timer", dbName(), this);
1451	lockDb();
1452}
1453
1454void KeychainDbCommon::activity()
1455{
1456    if (!isLocked()) {
1457		secdebug("KCdb", "setting DbCommon %p timer to %d",
1458			this, int(mParams.idleTimeout));
1459		Server::active().setTimer(this, Time::Interval(int(mParams.idleTimeout)));
1460	}
1461}
1462
1463void KeychainDbCommon::sleepProcessing()
1464{
1465	secdebug("KCdb", "common %s(%p) sleep-lock processing", dbName(), this);
1466	StLock<Mutex> _(*this);
1467	if (mParams.lockOnSleep)
1468		lockDb();
1469}
1470
1471void KeychainDbCommon::lockProcessing()
1472{
1473	lockDb();
1474}
1475
1476
1477//
1478// We consider a keychain to belong to the system domain if it resides
1479// in /Library/Keychains. That's not exactly fool-proof, but we don't
1480// currently have any internal markers to interrogate.
1481//
1482bool KeychainDbCommon::belongsToSystem() const
1483{
1484	if (const char *name = this->dbName())
1485		return !strncmp(name, "/Library/Keychains/", 19);
1486	return false;
1487}
1488
1489
1490//
1491// Keychain global objects
1492//
1493KeychainDbGlobal::KeychainDbGlobal(const DbIdentifier &id)
1494	: mIdentifier(id)
1495{
1496}
1497
1498KeychainDbGlobal::~KeychainDbGlobal()
1499{
1500	secdebug("KCdb", "DbGlobal %p destroyed", this);
1501}
1502