2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
28 // kcdatabase - software database container implementation.
30 // General implementation notes:
31 // This leverages LocalDatabase/LocalKey for cryptography, and adds the
32 // storage coder/decoder logic that implements "keychain" databases in their
33 // intricately choreographed dance between securityd and the AppleCSPDL.
34 // As always, Database objects are lifetime-bound to their Process referent;
35 // they can also be destroyed explicitly with a client release call.
36 // DbCommons are reference-held by their Databases, with one extra special
37 // reference (from the Session) introduced when the database unlocks, and
38 // removed when it locks again. That way, an unused DbCommon dies when it
39 // is locked or when the Session dies, whichever happens earlier.
40 // There is (as yet) no global-scope Database object for Keychain databases.
42 #include "kcdatabase.h"
43 #include "agentquery.h"
47 #include "notifications.h"
48 #include <security_agent_client/agentclient.h>
49 #include <security_cdsa_utilities/acl_any.h> // for default owner ACLs
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>
60 // Create a Database object from initial parameters (create operation)
62 KeychainDatabase::KeychainDatabase(const DLDbIdentifier
&id
, const DBParameters
¶ms
, Process
&proc
,
63 const AccessCredentials
*cred
, const AclEntryPrototype
*owner
)
64 : LocalDatabase(proc
), mValidData(false), version(0), mBlob(NULL
)
66 // save a copy of the credentials for later access control
67 mCred
= DataWalkers::copy(cred
, Allocator::standard());
69 // create a new random signature to complete the DLDbIdentifier
70 DbBlob::Signature newSig
;
71 Server::active().random(newSig
.bytes
);
72 DbIdentifier
ident(id
, newSig
);
74 // create common block and initialize
75 RefPointer
<KeychainDbCommon
> newCommon
= new KeychainDbCommon(proc
.session(), ident
);
76 StLock
<Mutex
> _(*newCommon
);
78 // new common is now visible (in ident-map) but we hold its lock
80 // establish the new master secret
81 establishNewSecrets(cred
, SecurityAgent::newDatabase
);
83 // set initial database parameters
84 common().mParams
= params
;
86 // the common is "unlocked" now
87 common().makeNewSecrets();
89 // establish initial ACL
91 cssmSetInitial(*owner
);
93 cssmSetInitial(new AnyAclSubject());
96 // for now, create the blob immediately
99 proc
.addReference(*this);
100 secdebug("SSdb", "database %s(%p) created, common at %p",
101 common().dbName(), this, &common());
106 // Create a Database object from a database blob (decoding)
108 KeychainDatabase::KeychainDatabase(const DLDbIdentifier
&id
, const DbBlob
*blob
, Process
&proc
,
109 const AccessCredentials
*cred
)
110 : LocalDatabase(proc
), mValidData(false), version(0)
112 // perform basic validation on the incoming blob
114 blob
->validate(CSSMERR_APPLEDL_INVALID_DATABASE_BLOB
);
115 switch (blob
->version()) {
116 #if defined(COMPAT_OSX_10_0)
117 case blob
->version_MacOS_10_0
:
120 case blob
->version_MacOS_10_1
:
123 CssmError::throwMe(CSSMERR_APPLEDL_INCOMPATIBLE_DATABASE_BLOB
);
126 // save a copy of the credentials for later access control
127 mCred
= DataWalkers::copy(cred
, Allocator::standard());
128 mBlob
= blob
->copy();
130 // check to see if we already know about this database
131 DbIdentifier
ident(id
, blob
->randomSignature
);
132 Session
&session
= process().session();
133 StLock
<Mutex
> _(session
);
134 if (KeychainDbCommon
*dbcom
=
135 session
.findFirst
<KeychainDbCommon
, const DbIdentifier
&>(&KeychainDbCommon::identifier
, ident
)) {
137 //@@@ arbitrate sequence number here, perhaps update common().mParams
139 "open database %s(%p) version %lx at known common %p",
140 common().dbName(), this, blob
->version(), &common());
142 // DbCommon not present; make a new one
143 parent(*new KeychainDbCommon(proc
.session(), ident
));
144 common().mParams
= blob
->params
;
145 secdebug("SSdb", "open database %s(%p) version %lx with new common %p",
146 common().dbName(), this, blob
->version(), &common());
148 proc
.addReference(*this);
153 // Destroy a Database
155 KeychainDatabase::~KeychainDatabase()
157 secdebug("SSdb", "deleting database %s(%p) common %p",
158 common().dbName(), this, &common());
159 Allocator::standard().free(mCred
);
160 Allocator::standard().free(mBlob
);
165 // Basic Database virtual implementations
167 KeychainDbCommon
&KeychainDatabase::common() const
169 return parent
<KeychainDbCommon
>();
172 const char *KeychainDatabase::dbName() const
174 return common().dbName();
178 static inline KeychainKey
&myKey(Key
*key
)
180 return *safe_cast
<KeychainKey
*>(key
);
185 // (Re-)Authenticate the database. This changes the stored credentials.
187 void KeychainDatabase::authenticate(const AccessCredentials
*cred
)
189 StLock
<Mutex
> _(common());
190 AccessCredentials
*newCred
= DataWalkers::copy(cred
, Allocator::standard());
191 Allocator::standard().free(mCred
);
197 // Make a new KeychainKey
199 RefPointer
<Key
> KeychainDatabase::makeKey(const CssmKey
&newKey
,
200 uint32 moreAttributes
, const AclEntryPrototype
*owner
)
202 return new KeychainKey(*this, newKey
, moreAttributes
, owner
);
207 // Return the database blob, recalculating it as needed.
209 DbBlob
*KeychainDatabase::blob()
211 StLock
<Mutex
> _(common());
213 makeUnlocked(); // unlock to get master secret
214 encode(); // (re)encode blob if needed
216 activity(); // reset timeout
217 assert(validBlob()); // better have a valid blob now...
223 // Encode the current database as a blob.
224 // Note that this returns memory we own and keep.
225 // Caller must hold common lock.
227 void KeychainDatabase::encode()
229 DbBlob
*blob
= common().encode(*this);
230 Allocator::standard().free(mBlob
);
232 version
= common().version
;
233 secdebug("SSdb", "encoded database %p common %p(%s) version %ld params=(%ld,%d)",
234 this, &common(), dbName(), version
,
235 common().mParams
.idleTimeout
, common().mParams
.lockOnSleep
);
240 // Change the passphrase on a database
242 void KeychainDatabase::changePassphrase(const AccessCredentials
*cred
)
244 // get and hold the common lock (don't let other threads break in here)
245 StLock
<Mutex
> _(common());
247 // establish OLD secret - i.e. unlock the database
248 //@@@ do we want to leave the final lock state alone?
251 // establish NEW secret
252 establishNewSecrets(cred
, SecurityAgent::changePassphrase
);
253 common().version
++; // blob state changed
254 secdebug("SSdb", "Database %s(%p) master secret changed", common().dbName(), this);
255 encode(); // force rebuild of local blob
257 // send out a notification
258 notify(kNotificationEventPassphraseChanged
);
260 // I guess this counts as an activity
266 // Extract the database master key as a proper Key object.
268 RefPointer
<Key
> KeychainDatabase::extractMasterKey(Database
&db
,
269 const AccessCredentials
*cred
, const AclEntryPrototype
*owner
,
270 uint32 usage
, uint32 attrs
)
272 // get and hold common lock
273 StLock
<Mutex
> _(common());
275 // unlock to establish master secret
278 // extract the raw cryptographic key
279 CssmClient::WrapKey
wrap(Server::csp(), CSSM_ALGID_NONE
);
281 wrap(common().masterKey(), key
);
283 // make the key object and return it
284 return new KeychainKey(db
, key
, attrs
& Key::managedAttributes
, owner
);
289 // Construct a binary blob of moderate size that is suitable for constructing
290 // an index identifying this database.
291 // We construct this from the database's marker blob, which is created with
292 // the database is made, and stays stable thereafter.
293 // Note: Ownership of the index blob passes to the caller.
294 // @@@ This means that physical copies share this index.
296 void KeychainDatabase::getDbIndex(CssmData
&indexData
)
299 encode(); // force blob creation
301 CssmData signature
= CssmData::wrap(mBlob
->randomSignature
);
302 indexData
= CssmAutoData(Allocator::standard(), signature
).release();
307 // Unlock this database (if needed) by obtaining the master secret in some
308 // suitable way and then proceeding to unlock with it.
309 // Does absolutely nothing if the database is already unlocked.
310 // The makeUnlocked forms are identical except the assume the caller already
311 // holds the common lock.
313 void KeychainDatabase::unlockDb()
315 StLock
<Mutex
> _(common());
319 void KeychainDatabase::makeUnlocked()
321 return makeUnlocked(mCred
);
324 void KeychainDatabase::makeUnlocked(const AccessCredentials
*cred
)
327 secdebug("SSdb", "%p(%p) unlocking for makeUnlocked()", this, &common());
328 assert(mBlob
|| (mValidData
&& common().hasMaster()));
329 establishOldSecrets(cred
);
330 common().setUnlocked(); // mark unlocked
331 activity(); // set timeout timer
332 } else if (!mValidData
) { // need to decode to get our ACLs, master secret available
333 secdebug("SSdb", "%p(%p) is unlocked; decoding for makeUnlocked()", this, &common());
335 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
);
343 // The following unlock given an explicit passphrase, rather than using
344 // (special cred sample based) default procedures.
346 void KeychainDatabase::unlockDb(const CssmData
&passphrase
)
348 StLock
<Mutex
> _(common());
349 makeUnlocked(passphrase
);
352 void KeychainDatabase::makeUnlocked(const CssmData
&passphrase
)
355 if (decode(passphrase
))
358 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
);
359 } else if (!mValidData
) { // need to decode to get our ACLs, passphrase available
361 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
);
369 // Nonthrowing passphrase-based unlock. This returns false if unlock failed.
370 // Note that this requires an explicitly given passphrase.
371 // Caller must hold common lock.
373 bool KeychainDatabase::decode(const CssmData
&passphrase
)
376 common().setup(mBlob
, passphrase
);
382 // Given the established master secret, decode the working keys and other
383 // functional secrets for this database. Return false (do NOT throw) if
384 // the decode fails. Call this in low(er) level code once you established
387 bool KeychainDatabase::decode()
390 assert(common().hasMaster());
391 void *privateAclBlob
;
392 if (common().unlockDb(mBlob
, &privateAclBlob
)) {
394 importBlob(mBlob
->publicAclBlob(), privateAclBlob
);
397 Allocator::standard().free(privateAclBlob
);
400 secdebug("SSdb", "%p decode failed", this);
406 // Given an AccessCredentials for this database, wring out the existing primary
407 // database secret by whatever means necessary.
408 // On entry, caller must hold the database common lock. It will be held throughout.
409 // On exit, the crypto core has its master secret. If things go wrong,
410 // we will throw a suitable exception. Note that encountering any malformed
411 // credential sample will throw, but this is not guaranteed -- don't assume
412 // that NOT throwing means creds is entirely well-formed (it may just be good
413 // enough to work THIS time).
416 // Walk through the creds. Fish out those credentials (in order) that
417 // are for unlock processing (they have no ACL subject correspondents),
418 // and (try to) obey each in turn, until one produces a valid secret
419 // or you run out. If no special samples are found at all, interpret that as
420 // "use the system global default," which happens to be hard-coded right here.
422 void KeychainDatabase::establishOldSecrets(const AccessCredentials
*creds
)
424 list
<CssmSample
> samples
;
425 if (creds
&& creds
->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK
, samples
)) {
426 for (list
<CssmSample
>::iterator it
= samples
.begin(); it
!= samples
.end(); it
++) {
427 TypedList
&sample
= *it
;
428 sample
.checkProper();
429 switch (sample
.type()) {
430 // interactively prompt the user - no additional data
431 case CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT
:
433 secdebug("SSdb", "%p attempting interactive unlock", this);
434 QueryUnlock
query(*this);
435 query
.inferHints(Server::process());
436 if (query() == SecurityAgent::noReason
)
440 // try to use an explicitly given passphrase - Data:passphrase
441 case CSSM_SAMPLE_TYPE_PASSWORD
:
442 if (sample
.length() != 2)
443 CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
);
444 secdebug("SSdb", "%p attempting passphrase unlock", this);
445 if (decode(sample
[1]))
448 // try to open with a given master key - Data:CSP or KeyHandle, Data:CssmKey
449 case CSSM_WORDID_SYMMETRIC_KEY
:
451 secdebug("SSdb", "%p attempting explicit key unlock", this);
452 common().setup(mBlob
, keyFromCreds(sample
));
456 // explicitly defeat the default action but don't try anything in particular
457 case CSSM_WORDID_CANCELED
:
458 secdebug("SSdb", "%p defeat default action", this);
461 // Unknown sub-sample for unlocking.
462 // If we wanted to be fascist, we could now do
463 // CssmError::throwMe(CSSM_ERRCODE_SAMPLE_VALUE_NOT_SUPPORTED);
464 // But instead we try to be tolerant and continue on.
465 // This DOES however count as an explicit attempt at specifying unlock,
466 // so we will no longer try the default case below...
467 secdebug("SSdb", "%p unknown sub-sample unlock (%ld) ignored", this, sample
.type());
475 // attempt system-keychain unlock
476 SystemKeychainKey
systemKeychain(kSystemUnlockFile
);
477 if (systemKeychain
.matches(mBlob
->randomSignature
)) {
478 secdebug("SSdb", "%p attempting system unlock", this);
479 common().setup(mBlob
, CssmClient::Key(Server::csp(), systemKeychain
.key(), true));
484 // attempt interactive unlock
485 QueryUnlock
query(*this);
486 query
.inferHints(Server::process());
487 if (query() == SecurityAgent::noReason
)
491 // out of options - no secret obtained
492 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
);
497 // Same thing, but obtain a new secret somehow and set it into the common.
499 void KeychainDatabase::establishNewSecrets(const AccessCredentials
*creds
, SecurityAgent::Reason reason
)
501 list
<CssmSample
> samples
;
502 if (creds
&& creds
->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK
, samples
)) {
503 for (list
<CssmSample
>::iterator it
= samples
.begin(); it
!= samples
.end(); it
++) {
504 TypedList
&sample
= *it
;
505 sample
.checkProper();
506 switch (sample
.type()) {
507 // interactively prompt the user
508 case CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT
:
510 secdebug("SSdb", "%p specified interactive passphrase", this);
511 QueryNewPassphrase
query(*this, reason
);
512 query
.inferHints(Server::process());
513 CssmAutoData
passphrase(Allocator::standard(Allocator::sensitive
));
514 if (query(passphrase
) == SecurityAgent::noReason
) {
515 common().setup(NULL
, passphrase
);
520 // try to use an explicitly given passphrase
521 case CSSM_SAMPLE_TYPE_PASSWORD
:
522 secdebug("SSdb", "%p specified explicit passphrase", this);
523 if (sample
.length() != 2)
524 CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
);
525 common().setup(NULL
, sample
[1]);
527 // try to open with a given master key
528 case CSSM_WORDID_SYMMETRIC_KEY
:
529 secdebug("SSdb", "%p specified explicit master key", this);
530 common().setup(NULL
, keyFromCreds(sample
));
532 // explicitly defeat the default action but don't try anything in particular
533 case CSSM_WORDID_CANCELED
:
534 secdebug("SSdb", "%p defeat default action", this);
537 // Unknown sub-sample for acquiring new secret.
538 // If we wanted to be fascist, we could now do
539 // CssmError::throwMe(CSSM_ERRCODE_SAMPLE_VALUE_NOT_SUPPORTED);
540 // But instead we try to be tolerant and continue on.
541 // This DOES however count as an explicit attempt at specifying unlock,
542 // so we will no longer try the default case below...
543 secdebug("SSdb", "%p unknown sub-sample acquisition (%ld) ignored",
544 this, sample
.type());
549 // default action -- interactive (only)
550 QueryNewPassphrase
query(*this, reason
);
551 query
.inferHints(Server::process());
552 CssmAutoData
passphrase(Allocator::standard(Allocator::sensitive
));
553 if (query(passphrase
) == SecurityAgent::noReason
) {
554 common().setup(NULL
, passphrase
);
559 // out of options - no secret obtained
560 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
);
565 // Given a (truncated) Database credentials TypedList specifying a master key,
566 // locate the key and return a reference to it.
568 CssmClient::Key
KeychainDatabase::keyFromCreds(const TypedList
&sample
)
570 // decode TypedList structure (sample type; Data:CSPHandle; Data:CSSM_KEY)
571 assert(sample
.type() == CSSM_WORDID_SYMMETRIC_KEY
);
572 if (sample
.length() != 3
573 || sample
[1].type() != CSSM_LIST_ELEMENT_DATUM
574 || sample
[2].type() != CSSM_LIST_ELEMENT_DATUM
)
575 CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
);
576 CSSM_CSP_HANDLE
&handle
= *sample
[1].data().interpretedAs
<CSSM_CSP_HANDLE
>(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
);
577 CssmKey
&key
= *sample
[2].data().interpretedAs
<CssmKey
>(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
);
579 if (key
.header().cspGuid() == gGuidAppleCSPDL
) {
580 // handleOrKey is a SecurityServer KeyHandle; ignore key argument
581 return myKey(Server::key(handle
));
583 // not a KeyHandle reference; use key as a raw key
584 if (key
.header().blobType() != CSSM_KEYBLOB_RAW
)
585 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE
);
586 if (key
.header().keyClass() != CSSM_KEYCLASS_SESSION_KEY
)
587 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS
);
588 return CssmClient::Key(Server::csp(), key
, true);
594 // Verify a putative database passphrase.
595 // If the database is already unlocked, just check the passphrase.
596 // Otherwise, unlock with that passphrase and report success.
597 // Caller must hold the common lock.
599 bool KeychainDatabase::validatePassphrase(const CssmData
&passphrase
) const
601 if (common().hasMaster()) {
602 // verify against known secret
603 return common().validatePassphrase(passphrase
);
605 // no master secret - perform "blind" unlock to avoid actual unlock
607 DatabaseCryptoCore test
;
608 test
.setup(mBlob
, passphrase
);
609 test
.decodeCore(mBlob
, NULL
);
619 // Lock this database
621 void KeychainDatabase::lockDb()
628 // Given a Key for this database, encode it into a blob and return it.
630 KeyBlob
*KeychainDatabase::encodeKey(const CssmKey
&key
, const CssmData
&pubAcl
, const CssmData
&privAcl
)
634 // tell the cryptocore to form the key blob
635 return common().encodeKeyCore(key
, pubAcl
, privAcl
);
640 // Given a "blobbed" key for this database, decode it into its real
641 // key object and (re)populate its ACL.
643 void KeychainDatabase::decodeKey(KeyBlob
*blob
, CssmKey
&key
, void * &pubAcl
, void * &privAcl
)
645 unlockDb(); // we need our keys
647 common().decodeKeyCore(blob
, key
, pubAcl
, privAcl
);
648 // memory protocol: pubAcl points into blob; privAcl was allocated
655 // Modify database parameters
657 void KeychainDatabase::setParameters(const DBParameters
¶ms
)
659 StLock
<Mutex
> _(common());
661 common().mParams
= params
;
662 common().version
++; // invalidate old blobs
664 secdebug("SSdb", "%p common %p(%s) set params=(%ld,%d)",
665 this, &common(), dbName(), params
.idleTimeout
, params
.lockOnSleep
);
670 // Retrieve database parameters
672 void KeychainDatabase::getParameters(DBParameters
¶ms
)
674 StLock
<Mutex
> _(common());
676 params
= common().mParams
;
677 //activity(); // getting parameters does not reset the idle timer
682 // Intercept ACL change requests and reset blob validity
684 void KeychainDatabase::instantiateAcl()
686 StLock
<Mutex
> _(common());
690 void KeychainDatabase::changedAcl()
692 StLock
<Mutex
> _(common());
696 const Database
*KeychainDatabase::relatedDatabase() const
703 #if defined(DEBUGDUMP)
705 void KeychainDbCommon::dumpNode()
707 PerSession::dumpNode();
708 uint32 sig
; memcpy(&sig
, &mIdentifier
.signature(), sizeof(sig
));
709 Debug::dump(" %s[%8.8lx]", mIdentifier
.dbName(), sig
);
711 Debug::dump(" locked");
713 time_t whenTime
= time_t(when());
714 Debug::dump(" unlocked(%24.24s/%.2g)", ctime(&whenTime
),
715 (when() - Time::now()).seconds());
717 Debug::dump(" params=(%ld,%d)", mParams
.idleTimeout
, mParams
.lockOnSleep
);
720 void KeychainDatabase::dumpNode()
722 PerProcess::dumpNode();
723 Debug::dump(" %s vers=%ld",
724 mValidData
? " data" : " nodata", version
);
726 uint32 sig
; memcpy(&sig
, &mBlob
->randomSignature
, sizeof(sig
));
727 Debug::dump(" blob=%p[%8.8lx]", mBlob
, sig
);
729 Debug::dump(" noblob");
737 // DbCommon basic features
739 KeychainDbCommon::KeychainDbCommon(Session
&ssn
, const DbIdentifier
&id
)
740 : DbCommon(ssn
), mIdentifier(id
), sequence(0), version(1),
741 mIsLocked(true), mValidParams(false)
744 KeychainDbCommon::~KeychainDbCommon()
746 secdebug("SSdb", "DbCommon %p destroyed", this);
748 // explicitly unschedule ourselves
749 Server::active().clearTimer(this);
753 void KeychainDbCommon::makeNewSecrets()
755 // we already have a master key (right?)
758 // tell crypto core to generate the use keys
759 DatabaseCryptoCore::generateNewSecrets();
761 // we're now officially "unlocked"; set the timer
763 activity(); // set lock timer
768 // All unlocking activity ultimately funnels through this method.
769 // This unlocks a DbCommon using the secrets setup in its crypto core
770 // component, and performs all the housekeeping needed to represent
772 // Returns true if unlock was successful, false if it failed due to
773 // invalid/insufficient secrets. Throws on other errors.
775 bool KeychainDbCommon::unlockDb(DbBlob
*blob
, void **privateAclBlob
)
778 // Tell the cryptocore to (try to) decode itself. This will fail
779 // in an astonishing variety of ways if the passphrase is wrong.
781 decodeCore(blob
, privateAclBlob
);
782 secdebug("SSdb", "%p unlock successful", this);
784 secdebug("SSdb", "%p unlock failed", this);
788 // get the database parameters only if we haven't got them yet
790 mParams
= blob
->params
;
791 n2hi(mParams
.idleTimeout
);
792 mValidParams
= true; // sticky
795 setUnlocked(); // mark unlocked
796 activity(); // set lock timer
798 // broadcast unlock notification
799 notify(kNotificationEventUnlocked
);
803 void KeychainDbCommon::setUnlocked()
805 session().addReference(*this); // active/held
806 mIsLocked
= false; // mark unlocked
810 void KeychainDbCommon::lockDb(bool forSleep
)
812 StLock
<Mutex
> locker(*this);
814 if (forSleep
&& !mParams
.lockOnSleep
)
815 return; // it doesn't want to
817 DatabaseCryptoCore::invalidate();
818 notify(kNotificationEventLocked
);
819 Server::active().clearTimer(this);
821 mIsLocked
= true; // mark locked
822 locker
.unlock(); // release DbCommon lock now
823 session().removeReference(*this); // remove active/hold
828 DbBlob
*KeychainDbCommon::encode(KeychainDatabase
&db
)
830 assert(!isLocked()); // must have been unlocked by caller
832 // export database ACL to blob form
833 CssmData pubAcl
, privAcl
;
834 db
.exportBlob(pubAcl
, privAcl
);
836 // tell the cryptocore to form the blob
838 form
.randomSignature
= identifier();
839 form
.sequence
= sequence
;
840 form
.params
= mParams
;
841 h2ni(form
.params
.idleTimeout
);
844 DbBlob
*blob
= encodeCore(form
, pubAcl
, privAcl
);
847 db
.allocator
.free(pubAcl
);
848 db
.allocator
.free(privAcl
);
854 // Send a keychain-related notification event about this keychain
856 void KeychainDbCommon::notify(NotificationEvent event
)
858 // form the data (encoded DLDbIdentifier)
859 NameValueDictionary nvd
;
860 NameValueDictionary::MakeNameValueDictionaryFromDLDbIdentifier(identifier(), nvd
);
864 // inject notification into Security event system
865 Listener::notify(kNotificationDomainDatabase
, event
, data
);
873 // Perform deferred lock processing for a database.
875 void KeychainDbCommon::action()
877 secdebug("SSdb", "common %s(%p) locked by timer", dbName(), this);
881 void KeychainDbCommon::activity()
884 secdebug("SSdb", "setting DbCommon %p timer to %d",
885 this, int(mParams
.idleTimeout
));
886 Server::active().setTimer(this, Time::Interval(int(mParams
.idleTimeout
)));
890 void KeychainDbCommon::sleepProcessing()