2 * Copyright (c) 2000-2007 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
26 // kcdatabase - software database container implementation.
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.
40 #include "kcdatabase.h"
41 #include "agentquery.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>
58 void unflattenKey(const CssmData
&flatKey
, CssmKey
&rawKey
); //>> make static method on KeychainDatabase
61 // Create a Database object from initial parameters (create operation)
63 KeychainDatabase::KeychainDatabase(const DLDbIdentifier
&id
, const DBParameters
¶ms
, Process
&proc
,
64 const AccessCredentials
*cred
, const AclEntryPrototype
*owner
)
65 : LocalDatabase(proc
), mValidData(false), version(0), mBlob(NULL
)
67 // save a copy of the credentials for later access control
68 mCred
= DataWalkers::copy(cred
, Allocator::standard());
70 // create a new random signature to complete the DLDbIdentifier
71 DbBlob::Signature newSig
;
72 Server::active().random(newSig
.bytes
);
73 DbIdentifier
ident(id
, newSig
);
75 // create common block and initialize
76 RefPointer
<KeychainDbCommon
> newCommon
= new KeychainDbCommon(proc
.session(), ident
);
77 StLock
<Mutex
> _(*newCommon
);
79 // new common is now visible (in ident-map) but we hold its lock
81 // establish the new master secret
82 establishNewSecrets(cred
, SecurityAgent::newDatabase
);
84 // set initial database parameters
85 common().mParams
= params
;
87 // the common is "unlocked" now
88 common().makeNewSecrets();
90 // establish initial ACL
92 acl().cssmSetInitial(*owner
);
94 acl().cssmSetInitial(new AnyAclSubject());
97 // for now, create the blob immediately
100 proc
.addReference(*this);
102 // this new keychain is unlocked; make it so
105 secdebug("KCdb", "database %s(%p) created, common at %p",
106 common().dbName(), this, &common());
111 // Create a Database object from a database blob (decoding)
113 KeychainDatabase::KeychainDatabase(const DLDbIdentifier
&id
, const DbBlob
*blob
, Process
&proc
,
114 const AccessCredentials
*cred
)
115 : LocalDatabase(proc
), mValidData(false), version(0)
119 // save a copy of the credentials for later access control
120 mCred
= DataWalkers::copy(cred
, Allocator::standard());
121 mBlob
= blob
->copy();
123 // check to see if we already know about this database
124 DbIdentifier
ident(id
, blob
->randomSignature
);
125 Session
&session
= process().session();
126 StLock
<Mutex
> _(session
);
127 if (KeychainDbCommon
*dbcom
=
128 session
.findFirst
<KeychainDbCommon
, const DbIdentifier
&>(&KeychainDbCommon::identifier
, ident
)) {
130 //@@@ arbitrate sequence number here, perhaps update common().mParams
132 "open database %s(%p) version %x at known common %p",
133 common().dbName(), this, blob
->version(), &common());
135 // DbCommon not present; make a new one
136 parent(*new KeychainDbCommon(proc
.session(), ident
));
137 common().mParams
= blob
->params
;
138 secdebug("KCdb", "open database %s(%p) version %x with new common %p",
139 common().dbName(), this, blob
->version(), &common());
140 // this DbCommon is locked; no timer or reference setting
142 proc
.addReference(*this);
147 // Special-purpose constructor for keychain synchronization. Copies an
148 // existing keychain but uses the operational keys from secretsBlob. The
149 // new KeychainDatabase will silently replace the existing KeychainDatabase
150 // as soon as the client declares that re-encoding of all keychain items is
151 // finished. This is a little perilous since it allows a client to dictate
152 // securityd state, but we try to ensure that only the client that started
153 // the re-encoding can declare it done.
155 KeychainDatabase::KeychainDatabase(KeychainDatabase
&src
, Process
&proc
,
156 const DbBlob
*secretsBlob
, const CssmData
&agentData
)
157 : LocalDatabase(proc
), mValidData(false), version(0), mBlob(NULL
)
159 validateBlob(secretsBlob
);
161 // get the passphrase to unlock secretsBlob
162 QueryDBBlobSecret query
;
163 query
.inferHints(proc
);
164 query
.addHint(AGENT_HINT_KCSYNC_DICT
, agentData
.data(), agentData
.length());
165 DatabaseCryptoCore keysCore
;
166 if (query(keysCore
, secretsBlob
) != SecurityAgent::noReason
)
167 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
);
168 // keysCore is now ready to yield its secrets to us
170 mCred
= DataWalkers::copy(src
.mCred
, Allocator::standard());
172 // Give this KeychainDatabase a temporary name
173 std::string newDbName
= std::string("////") + std::string(src
.identifier().dbName());
174 DLDbIdentifier
newDLDbIdent(src
.identifier().dlDbIdentifier().ssuid(), newDbName
.c_str(), src
.identifier().dlDbIdentifier().dbLocation());
175 DbIdentifier
ident(newDLDbIdent
, src
.identifier());
177 // create common block and initialize
178 RefPointer
<KeychainDbCommon
> newCommon
= new KeychainDbCommon(proc
.session(), ident
);
179 StLock
<Mutex
> _(*newCommon
);
182 // set initial database parameters from the source keychain
183 common().mParams
= src
.common().mParams
;
185 // establish the source keychain's master secret as ours
186 // @@@ NB: this is a v. 0.1 assumption. We *should* trigger new UI
187 // that offers the user the option of using the existing password
188 // or choosing a new one. That would require a new
189 // SecurityAgentQuery type, new UI, and--possibly--modifications to
190 // ensure that the new password is available here to generate the
191 // new master secret.
192 src
.unlockDb(); // precaution for masterKey()
193 common().setup(src
.blob(), src
.common().masterKey());
195 // import the operational secrets
196 common().importSecrets(keysCore
);
198 // import source keychain's ACL
199 CssmData pubAcl
, privAcl
;
200 src
.acl().exportBlob(pubAcl
, privAcl
);
201 importBlob(pubAcl
.data(), privAcl
.data());
202 src
.acl().allocator
.free(pubAcl
);
203 src
.acl().allocator
.free(privAcl
);
205 // indicate that this keychain should be allowed to do some otherwise
206 // risky things required for copying, like re-encoding keys
207 mRecodingSource
= &src
;
209 common().setUnlocked();
214 proc
.addReference(*this);
215 secdebug("SSdb", "database %s(%p) created as copy, common at %p",
216 common().dbName(), this, &common());
221 // Destroy a Database
223 KeychainDatabase::~KeychainDatabase()
225 secdebug("KCdb", "deleting database %s(%p) common %p",
226 common().dbName(), this, &common());
227 Allocator::standard().free(mCred
);
228 Allocator::standard().free(mBlob
);
233 // Basic Database virtual implementations
235 KeychainDbCommon
&KeychainDatabase::common() const
237 return parent
<KeychainDbCommon
>();
240 const char *KeychainDatabase::dbName() const
242 return common().dbName();
245 bool KeychainDatabase::transient() const
247 return false; // has permanent store
250 AclKind
KeychainDatabase::aclKind() const
255 Database
*KeychainDatabase::relatedDatabase()
261 static inline KeychainKey
&myKey(Key
*key
)
263 return *safe_cast
<KeychainKey
*>(key
);
268 // (Re-)Authenticate the database. This changes the stored credentials.
270 void KeychainDatabase::authenticate(CSSM_DB_ACCESS_TYPE mode
,
271 const AccessCredentials
*cred
)
273 StLock
<Mutex
> _(common());
275 // the (Apple specific) RESET bit means "lock the database now"
277 case CSSM_DB_ACCESS_RESET
:
278 secdebug("KCdb", "%p ACCESS_RESET triggers keychain lock", this);
282 // store the new credentials for future use
283 secdebug("KCdb", "%p authenticate stores new database credentials", this);
284 AccessCredentials
*newCred
= DataWalkers::copy(cred
, Allocator::standard());
285 Allocator::standard().free(mCred
);
292 // Make a new KeychainKey.
293 // If PERMANENT is off, make a temporary key instead.
294 // The db argument allows you to create for another KeychainDatabase (only);
295 // it defaults to ourselves.
297 RefPointer
<Key
> KeychainDatabase::makeKey(Database
&db
, const CssmKey
&newKey
,
298 uint32 moreAttributes
, const AclEntryPrototype
*owner
)
301 if (moreAttributes
& CSSM_KEYATTR_PERMANENT
)
302 return new KeychainKey(db
, newKey
, moreAttributes
, owner
);
304 return process().makeTemporaryKey(newKey
, moreAttributes
, owner
);
307 RefPointer
<Key
> KeychainDatabase::makeKey(const CssmKey
&newKey
,
308 uint32 moreAttributes
, const AclEntryPrototype
*owner
)
310 return makeKey(*this, newKey
, moreAttributes
, owner
);
315 // Return the database blob, recalculating it as needed.
317 DbBlob
*KeychainDatabase::blob()
319 StLock
<Mutex
> _(common());
321 makeUnlocked(); // unlock to get master secret
322 encode(); // (re)encode blob if needed
324 activity(); // reset timeout
325 assert(validBlob()); // better have a valid blob now...
331 // Encode the current database as a blob.
332 // Note that this returns memory we own and keep.
333 // Caller must hold common lock.
335 void KeychainDatabase::encode()
337 DbBlob
*blob
= common().encode(*this);
338 Allocator::standard().free(mBlob
);
340 version
= common().version
;
341 secdebug("KCdb", "encoded database %p common %p(%s) version %u params=(%u,%u)",
342 this, &common(), dbName(), version
,
343 common().mParams
.idleTimeout
, common().mParams
.lockOnSleep
);
348 // Change the passphrase on a database
350 void KeychainDatabase::changePassphrase(const AccessCredentials
*cred
)
352 // get and hold the common lock (don't let other threads break in here)
353 StLock
<Mutex
> _(common());
355 // establish OLD secret - i.e. unlock the database
356 //@@@ do we want to leave the final lock state alone?
359 // establish NEW secret
360 establishNewSecrets(cred
, SecurityAgent::changePassphrase
);
361 common().invalidateBlob(); // blob state changed
362 secdebug("KCdb", "Database %s(%p) master secret changed", common().dbName(), this);
363 encode(); // force rebuild of local blob
365 // send out a notification
366 notify(kNotificationEventPassphraseChanged
);
368 // I guess this counts as an activity
373 // Second stage of keychain synchronization: overwrite the original keychain's
374 // (this KeychainDatabase's) operational secrets
376 void KeychainDatabase::commitSecretsForSync(KeychainDatabase
&cloneDb
)
378 StLock
<Mutex
> _(common());
380 // try to detect spoofing
381 if (cloneDb
.mRecodingSource
!= this)
382 CssmError::throwMe(CSSM_ERRCODE_INVALID_DB_HANDLE
);
384 // in case we autolocked since starting the sync
388 // Decode all keys whose handles refer to this on-disk keychain so that
389 // if the holding client commits the key back to disk, it's encoded with
390 // the new operational secrets. The recoding client *must* hold a write
391 // lock for the on-disk keychain from the moment it starts recoding key
392 // items until after this call.
394 // @@@ This specific implementation is a workaround for 4003540.
395 std::vector
<CSSM_HANDLE
> handleList
;
396 HandleObject::findAllRefs
<KeychainKey
>(handleList
);
397 size_t count
= handleList
.size();
399 for (unsigned int n
= 0; n
< count
; ++n
) {
400 RefPointer
<KeychainKey
> kckey
=
401 HandleObject::findRefAndLock
<KeychainKey
>(handleList
[n
], CSSMERR_CSP_INVALID_KEY_REFERENCE
);
402 StLock
<Mutex
> _(*kckey
/*, true*/);
403 if (kckey
->database().global().identifier() == identifier()) {
404 kckey
->key(); // force decode
405 kckey
->invalidateBlob();
406 secdebug("kcrecode", "changed extant key %p (proc %d)",
407 &*kckey
, kckey
->process().pid());
412 // it is now safe to replace the old op secrets
413 common().importSecrets(cloneDb
.common());
414 common().invalidateBlob();
419 // Extract the database master key as a proper Key object.
421 RefPointer
<Key
> KeychainDatabase::extractMasterKey(Database
&db
,
422 const AccessCredentials
*cred
, const AclEntryPrototype
*owner
,
423 uint32 usage
, uint32 attrs
)
425 // get and hold common lock
426 StLock
<Mutex
> _(common());
428 // force lock to require re-validation of credentials
431 // unlock to establish master secret
434 // extract the raw cryptographic key
435 CssmClient::WrapKey
wrap(Server::csp(), CSSM_ALGID_NONE
);
437 wrap(common().masterKey(), key
);
439 // make the key object and return it
440 return makeKey(db
, key
, attrs
& LocalKey::managedAttributes
, owner
);
445 // Unlock this database (if needed) by obtaining the master secret in some
446 // suitable way and then proceeding to unlock with it.
447 // Does absolutely nothing if the database is already unlocked.
448 // The makeUnlocked forms are identical except the assume the caller already
449 // holds the common lock.
451 void KeychainDatabase::unlockDb()
453 StLock
<Mutex
> _(common());
457 void KeychainDatabase::makeUnlocked()
459 return makeUnlocked(mCred
);
462 void KeychainDatabase::makeUnlocked(const AccessCredentials
*cred
)
465 secdebug("KCdb", "%p(%p) unlocking for makeUnlocked()", this, &common());
466 assert(mBlob
|| (mValidData
&& common().hasMaster()));
467 establishOldSecrets(cred
);
468 common().setUnlocked(); // mark unlocked
470 if (!mValidData
) { // need to decode to get our ACLs, master secret available
471 secdebug("KCdb", "%p(%p) is unlocked; decoding for makeUnlocked()", this, &common());
473 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
);
481 // The following unlock given an explicit passphrase, rather than using
482 // (special cred sample based) default procedures.
484 void KeychainDatabase::unlockDb(const CssmData
&passphrase
)
486 StLock
<Mutex
> _(common());
487 makeUnlocked(passphrase
);
490 void KeychainDatabase::makeUnlocked(const CssmData
&passphrase
)
493 if (decode(passphrase
))
496 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
);
497 } else if (!mValidData
) { // need to decode to get our ACLs, passphrase available
499 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
);
507 // Nonthrowing passphrase-based unlock. This returns false if unlock failed.
508 // Note that this requires an explicitly given passphrase.
509 // Caller must hold common lock.
511 bool KeychainDatabase::decode(const CssmData
&passphrase
)
514 common().setup(mBlob
, passphrase
);
520 // Given the established master secret, decode the working keys and other
521 // functional secrets for this database. Return false (do NOT throw) if
522 // the decode fails. Call this in low(er) level code once you established
525 bool KeychainDatabase::decode()
528 assert(common().hasMaster());
529 void *privateAclBlob
;
530 if (common().unlockDb(mBlob
, &privateAclBlob
)) {
532 acl().importBlob(mBlob
->publicAclBlob(), privateAclBlob
);
535 Allocator::standard().free(privateAclBlob
);
538 secdebug("KCdb", "%p decode failed", this);
544 // Given an AccessCredentials for this database, wring out the existing primary
545 // database secret by whatever means necessary.
546 // On entry, caller must hold the database common lock. It will be held
547 // throughout except when user interaction is required. User interaction
548 // requires relinquishing the database common lock and taking the UI lock. On
549 // return from user interaction, the UI lock is relinquished and the database
550 // common lock must be reacquired. At no time may the caller hold both locks.
551 // On exit, the crypto core has its master secret. If things go wrong,
552 // we will throw a suitable exception. Note that encountering any malformed
553 // credential sample will throw, but this is not guaranteed -- don't assume
554 // that NOT throwing means creds is entirely well-formed (it may just be good
555 // enough to work THIS time).
558 // Walk through the creds. Fish out those credentials (in order) that
559 // are for unlock processing (they have no ACL subject correspondents),
560 // and (try to) obey each in turn, until one produces a valid secret
561 // or you run out. If no special samples are found at all, interpret that as
562 // "use the system global default," which happens to be hard-coded right here.
564 void KeychainDatabase::establishOldSecrets(const AccessCredentials
*creds
)
566 list
<CssmSample
> samples
;
567 if (creds
&& creds
->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK
, samples
)) {
568 for (list
<CssmSample
>::iterator it
= samples
.begin(); it
!= samples
.end(); it
++) {
569 TypedList
&sample
= *it
;
570 sample
.checkProper();
571 switch (sample
.type()) {
572 // interactively prompt the user - no additional data
573 case CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT
:
574 if (interactiveUnlock())
577 // try to use an explicitly given passphrase - Data:passphrase
578 case CSSM_SAMPLE_TYPE_PASSWORD
:
579 if (sample
.length() != 2)
580 CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
);
581 secdebug("KCdb", "%p attempting passphrase unlock", this);
582 if (decode(sample
[1]))
585 // try to open with a given master key - Data:CSP or KeyHandle, Data:CssmKey
586 case CSSM_SAMPLE_TYPE_SYMMETRIC_KEY
:
587 case CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY
:
589 secdebug("KCdb", "%p attempting explicit key unlock", this);
590 common().setup(mBlob
, keyFromCreds(sample
, 4));
594 // explicitly defeat the default action but don't try anything in particular
595 case CSSM_WORDID_CANCELED
:
596 secdebug("KCdb", "%p defeat default action", this);
599 // Unknown sub-sample for unlocking.
600 // If we wanted to be fascist, we could now do
601 // CssmError::throwMe(CSSM_ERRCODE_SAMPLE_VALUE_NOT_SUPPORTED);
602 // But instead we try to be tolerant and continue on.
603 // This DOES however count as an explicit attempt at specifying unlock,
604 // so we will no longer try the default case below...
605 secdebug("KCdb", "%p unknown sub-sample unlock (%d) ignored", this, sample
.type());
613 // attempt system-keychain unlock
614 SystemKeychainKey
systemKeychain(kSystemUnlockFile
);
615 if (systemKeychain
.matches(mBlob
->randomSignature
)) {
616 secdebug("KCdb", "%p attempting system unlock", this);
617 common().setup(mBlob
, CssmClient::Key(Server::csp(), systemKeychain
.key(), true));
622 if (interactiveUnlock())
626 // out of options - no secret obtained
627 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
);
630 bool KeychainDatabase::interactiveUnlock()
632 secdebug("KCdb", "%p attempting interactive unlock", this);
633 QueryUnlock
query(*this);
634 // take UI interlock and release DbCommon lock (to avoid deadlocks)
635 StSyncLock
<Mutex
, Mutex
> uisync(common().uiLock(), common());
637 // now that we have the UI lock, interact unless another thread unlocked us first
639 query
.inferHints(Server::process());
640 return query() == SecurityAgent::noReason
;
642 secdebug("KCdb", "%p was unlocked during uiLock delay", this);
649 // Same thing, but obtain a new secret somehow and set it into the common.
651 void KeychainDatabase::establishNewSecrets(const AccessCredentials
*creds
, SecurityAgent::Reason reason
)
653 list
<CssmSample
> samples
;
654 if (creds
&& creds
->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK
, samples
)) {
655 for (list
<CssmSample
>::iterator it
= samples
.begin(); it
!= samples
.end(); it
++) {
656 TypedList
&sample
= *it
;
657 sample
.checkProper();
658 switch (sample
.type()) {
659 // interactively prompt the user
660 case CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT
:
662 secdebug("KCdb", "%p specified interactive passphrase", this);
663 QueryNewPassphrase
query(*this, reason
);
664 StSyncLock
<Mutex
, Mutex
> uisync(common().uiLock(), common());
665 query
.inferHints(Server::process());
666 CssmAutoData
passphrase(Allocator::standard(Allocator::sensitive
));
667 if (query(passphrase
) == SecurityAgent::noReason
) {
668 common().setup(NULL
, passphrase
);
673 // try to use an explicitly given passphrase
674 case CSSM_SAMPLE_TYPE_PASSWORD
:
675 secdebug("KCdb", "%p specified explicit passphrase", this);
676 if (sample
.length() != 2)
677 CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
);
678 common().setup(NULL
, sample
[1]);
680 // try to open with a given master key
681 case CSSM_WORDID_SYMMETRIC_KEY
:
682 case CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY
:
683 secdebug("KCdb", "%p specified explicit master key", this);
684 common().setup(NULL
, keyFromCreds(sample
, 3));
686 // explicitly defeat the default action but don't try anything in particular
687 case CSSM_WORDID_CANCELED
:
688 secdebug("KCdb", "%p defeat default action", this);
691 // Unknown sub-sample for acquiring new secret.
692 // If we wanted to be fascist, we could now do
693 // CssmError::throwMe(CSSM_ERRCODE_SAMPLE_VALUE_NOT_SUPPORTED);
694 // But instead we try to be tolerant and continue on.
695 // This DOES however count as an explicit attempt at specifying unlock,
696 // so we will no longer try the default case below...
697 secdebug("KCdb", "%p unknown sub-sample acquisition (%d) ignored",
698 this, sample
.type());
703 // default action -- interactive (only)
704 QueryNewPassphrase
query(*this, reason
);
705 StSyncLock
<Mutex
, Mutex
> uisync(common().uiLock(), common());
706 query
.inferHints(Server::process());
707 CssmAutoData
passphrase(Allocator::standard(Allocator::sensitive
));
708 if (query(passphrase
) == SecurityAgent::noReason
) {
709 common().setup(NULL
, passphrase
);
714 // out of options - no secret obtained
715 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
);
720 // Given a (truncated) Database credentials TypedList specifying a master key,
721 // locate the key and return a reference to it.
723 CssmClient::Key
KeychainDatabase::keyFromCreds(const TypedList
&sample
, unsigned int requiredLength
)
725 // decode TypedList structure (sample type; Data:CSPHandle; Data:CSSM_KEY)
726 assert(sample
.type() == CSSM_SAMPLE_TYPE_SYMMETRIC_KEY
|| sample
.type() == CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY
);
727 if (sample
.length() != requiredLength
728 || sample
[1].type() != CSSM_LIST_ELEMENT_DATUM
729 || sample
[2].type() != CSSM_LIST_ELEMENT_DATUM
730 || (requiredLength
== 4 && sample
[3].type() != CSSM_LIST_ELEMENT_DATUM
))
731 CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
);
732 CSSM_CSP_HANDLE
&handle
= *sample
[1].data().interpretedAs
<CSSM_CSP_HANDLE
>(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
);
733 CssmKey
&key
= *sample
[2].data().interpretedAs
<CssmKey
>(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
);
735 if (key
.header().cspGuid() == gGuidAppleCSPDL
) {
736 // handleOrKey is a SecurityServer KeyHandle; ignore key argument
737 return safer_cast
<LocalKey
&>(*Server::key(handle
));
739 if (sample
.type() == CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY
) {
741 Contents (see DefaultCredentials::unlockKey in libsecurity_keychain/defaultcreds.cpp)
743 sample[0] sample type
744 sample[1] csp handle for master or wrapping key; is really a keyhandle
745 sample[2] masterKey [not used since securityd cannot interpret; use sample[1] handle instead]
746 sample[3] UnlockReferralRecord data, in this case the flattened symmetric key
749 // RefPointer<Key> Server::key(KeyHandle key)
750 KeyHandle keyhandle
= *sample
[1].data().interpretedAs
<KeyHandle
>(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
);
751 CssmData
&flattenedKey
= sample
[3].data();
752 RefPointer
<Key
> unwrappingKey
= Server::key(keyhandle
);
753 Database
&db
=unwrappingKey
->database();
755 CssmKey rawWrappedKey
;
756 unflattenKey(flattenedKey
, rawWrappedKey
);
758 RefPointer
<Key
> masterKey
;
759 CssmData emptyDescriptiveData
;
760 const AccessCredentials
*cred
= NULL
;
761 const AclEntryPrototype
*owner
= NULL
;
762 CSSM_KEYUSE usage
= CSSM_KEYUSE_ANY
;
763 CSSM_KEYATTR_FLAGS attrs
= CSSM_KEYATTR_EXTRACTABLE
; //CSSM_KEYATTR_RETURN_REF |
765 // Get default credentials for unwrappingKey (the one on the token)
766 // Copied from Statics::Statics() in libsecurity_keychain/aclclient.cpp
767 // Following KeyItem::getCredentials, one sees that the "operation" parameter
768 // e.g. "CSSM_ACL_AUTHORIZATION_DECRYPT" is ignored
769 Allocator
&alloc
= Allocator::standard();
770 AutoCredentials
promptCred(alloc
, 3);// enable interactive prompting
772 // promptCred: a credential permitting user prompt confirmations
774 // a KEYCHAIN_PROMPT sample, both by itself and in a THRESHOLD
775 // a PROMPTED_PASSWORD sample
776 promptCred
.sample(0) = TypedList(alloc
, CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT
);
777 promptCred
.sample(1) = TypedList(alloc
, CSSM_SAMPLE_TYPE_THRESHOLD
,
778 new(alloc
) ListElement(TypedList(alloc
, CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT
)));
779 promptCred
.sample(2) = TypedList(alloc
, CSSM_SAMPLE_TYPE_PROMPTED_PASSWORD
,
780 new(alloc
) ListElement(alloc
, CssmData()));
782 // This unwrap object is here just to provide a context
783 CssmClient::UnwrapKey
unwrap(Server::csp(), CSSM_ALGID_NONE
); //ok to lie about csp here
784 unwrap
.mode(CSSM_ALGMODE_NONE
);
785 unwrap
.padding(CSSM_PADDING_PKCS1
);
786 unwrap
.cred(promptCred
);
787 unwrap
.add(CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT
, uint32(CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7
));
788 Security::Context
*tmpContext
;
789 CSSM_CC_HANDLE CCHandle
= unwrap
.handle();
790 /*CSSM_RETURN rx = */ CSSM_GetContext (CCHandle
, (CSSM_CONTEXT_PTR
*)&tmpContext
);
792 // OK, this is skanky but necessary. We overwrite fields in the context struct
794 tmpContext
->ContextType
= CSSM_ALGCLASS_ASYMMETRIC
;
795 tmpContext
->AlgorithmType
= CSSM_ALGID_RSA
;
797 db
.unwrapKey(*tmpContext
, cred
, owner
, unwrappingKey
, NULL
, usage
, attrs
,
798 rawWrappedKey
, masterKey
, emptyDescriptiveData
);
800 Allocator::standard().free(rawWrappedKey
.KeyData
.Data
);
802 return safer_cast
<LocalKey
&>(*masterKey
).key();
806 // not a KeyHandle reference; use key as a raw key
807 if (key
.header().blobType() != CSSM_KEYBLOB_RAW
)
808 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE
);
809 if (key
.header().keyClass() != CSSM_KEYCLASS_SESSION_KEY
)
810 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS
);
811 return CssmClient::Key(Server::csp(), key
, true);
815 void unflattenKey(const CssmData
&flatKey
, CssmKey
&rawKey
)
817 // unflatten the raw input key naively: key header then key data
818 // We also convert it back to host byte order
819 // A CSSM_KEY is a CSSM_KEYHEADER followed by a CSSM_DATA
821 // Now copy: header, then key struct, then key data
822 memcpy(&rawKey
.KeyHeader
, flatKey
.Data
, sizeof(CSSM_KEYHEADER
));
823 memcpy(&rawKey
.KeyData
, flatKey
.Data
+ sizeof(CSSM_KEYHEADER
), sizeof(CSSM_DATA
));
824 const uint32 keyDataLength
= flatKey
.length() - sizeof(CSSM_KEY
);
825 rawKey
.KeyData
.Data
= Allocator::standard().malloc
<uint8
>(keyDataLength
);
826 rawKey
.KeyData
.Length
= keyDataLength
;
827 memcpy(rawKey
.KeyData
.Data
, flatKey
.Data
+ sizeof(CSSM_KEY
), keyDataLength
);
828 Security::n2hi(rawKey
.KeyHeader
); // convert it to host byte order
833 // Verify a putative database passphrase.
834 // If the database is already unlocked, just check the passphrase.
835 // Otherwise, unlock with that passphrase and report success.
836 // Caller must hold the common lock.
838 bool KeychainDatabase::validatePassphrase(const CssmData
&passphrase
) const
840 if (common().hasMaster()) {
841 // verify against known secret
842 return common().validatePassphrase(passphrase
);
844 // no master secret - perform "blind" unlock to avoid actual unlock
846 DatabaseCryptoCore test
;
847 test
.setup(mBlob
, passphrase
);
848 test
.decodeCore(mBlob
, NULL
);
858 // Lock this database
860 void KeychainDatabase::lockDb()
867 // Given a Key for this database, encode it into a blob and return it.
869 KeyBlob
*KeychainDatabase::encodeKey(const CssmKey
&key
, const CssmData
&pubAcl
, const CssmData
&privAcl
)
871 bool inTheClear
= false;
873 if((key
.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY
) &&
874 !(key
.attribute(CSSM_KEYATTR_PUBLIC_KEY_ENCRYPT
))) {
881 // tell the cryptocore to form the key blob
882 return common().encodeKeyCore(key
, pubAcl
, privAcl
, inTheClear
);
887 // Given a "blobbed" key for this database, decode it into its real
888 // key object and (re)populate its ACL.
890 void KeychainDatabase::decodeKey(KeyBlob
*blob
, CssmKey
&key
, void * &pubAcl
, void * &privAcl
)
892 if(!blob
->isClearText()) {
893 unlockDb(); // we need our keys
896 common().decodeKeyCore(blob
, key
, pubAcl
, privAcl
);
897 // memory protocol: pubAcl points into blob; privAcl was allocated
903 // Given a KeychainKey (that implicitly belongs to another keychain),
904 // return it encoded using this keychain's operational secrets.
906 KeyBlob
*KeychainDatabase::recodeKey(KeychainKey
&oldKey
)
908 if (mRecodingSource
!= &oldKey
.referent
<KeychainDatabase
>()) {
909 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
911 oldKey
.instantiateAcl(); // make sure key is decoded
912 CssmData publicAcl
, privateAcl
;
913 oldKey
.exportBlob(publicAcl
, privateAcl
);
914 // NB: blob's memory belongs to caller, not the common
917 * Make sure the new key is in the same cleartext/encrypted state.
919 bool inTheClear
= false;
920 assert(oldKey
.blob());
921 if(oldKey
.blob() && oldKey
.blob()->isClearText()) {
925 KeyBlob
*blob
= common().encodeKeyCore(oldKey
.cssmKey(), publicAcl
, privateAcl
, inTheClear
);
926 oldKey
.acl().allocator
.free(publicAcl
);
927 oldKey
.acl().allocator
.free(privateAcl
);
933 // Modify database parameters
935 void KeychainDatabase::setParameters(const DBParameters
¶ms
)
937 StLock
<Mutex
> _(common());
939 common().mParams
= params
;
940 common().invalidateBlob(); // invalidate old blobs
941 activity(); // (also resets the timeout timer)
942 secdebug("KCdb", "%p common %p(%s) set params=(%u,%u)",
943 this, &common(), dbName(), params
.idleTimeout
, params
.lockOnSleep
);
948 // Retrieve database parameters
950 void KeychainDatabase::getParameters(DBParameters
¶ms
)
952 StLock
<Mutex
> _(common());
954 params
= common().mParams
;
955 //activity(); // getting parameters does not reset the idle timer
960 // RIGHT NOW, database ACLs are attached to the database.
961 // This will soon move upstairs.
963 SecurityServerAcl
&KeychainDatabase::acl()
970 // Intercept ACL change requests and reset blob validity
972 void KeychainDatabase::instantiateAcl()
974 StLock
<Mutex
> _(common());
978 void KeychainDatabase::changedAcl()
980 StLock
<Mutex
> _(common());
986 // Check an incoming DbBlob for basic viability
988 void KeychainDatabase::validateBlob(const DbBlob
*blob
)
990 // perform basic validation on the blob
992 blob
->validate(CSSMERR_APPLEDL_INVALID_DATABASE_BLOB
);
993 switch (blob
->version()) {
994 #if defined(COMPAT_OSX_10_0)
995 case DbBlob::version_MacOS_10_0
:
998 case DbBlob::version_MacOS_10_1
:
1001 CssmError::throwMe(CSSMERR_APPLEDL_INCOMPATIBLE_DATABASE_BLOB
);
1007 // Debugging support
1009 #if defined(DEBUGDUMP)
1011 void KeychainDbCommon::dumpNode()
1013 PerSession::dumpNode();
1014 uint32 sig
; memcpy(&sig
, &mIdentifier
.signature(), sizeof(sig
));
1015 Debug::dump(" %s[%8.8x]", mIdentifier
.dbName(), sig
);
1017 Debug::dump(" locked");
1019 time_t whenTime
= time_t(when());
1020 Debug::dump(" unlocked(%24.24s/%.2g)", ctime(&whenTime
),
1021 (when() - Time::now()).seconds());
1023 Debug::dump(" params=(%u,%u)", mParams
.idleTimeout
, mParams
.lockOnSleep
);
1026 void KeychainDatabase::dumpNode()
1028 PerProcess::dumpNode();
1029 Debug::dump(" %s vers=%u",
1030 mValidData
? " data" : " nodata", version
);
1032 uint32 sig
; memcpy(&sig
, &mBlob
->randomSignature
, sizeof(sig
));
1033 Debug::dump(" blob=%p[%8.8x]", mBlob
, sig
);
1035 Debug::dump(" noblob");
1043 // DbCommon basic features
1045 KeychainDbCommon::KeychainDbCommon(Session
&ssn
, const DbIdentifier
&id
)
1046 : LocalDbCommon(ssn
), sequence(0), version(1), mIdentifier(id
),
1047 mIsLocked(true), mValidParams(false)
1049 // match existing DbGlobal or create a new one
1050 Server
&server
= Server::active();
1051 StLock
<Mutex
> _(server
);
1052 if (KeychainDbGlobal
*dbglobal
=
1053 server
.findFirst
<KeychainDbGlobal
, const DbIdentifier
&>(&KeychainDbGlobal::identifier
, identifier())) {
1055 secdebug("KCdb", "%p linking to existing DbGlobal %p", this, dbglobal
);
1057 // DbGlobal not present; make a new one
1058 parent(*new KeychainDbGlobal(identifier()));
1059 secdebug("KCdb", "%p linking to new DbGlobal %p", this, &global());
1062 // link lifetime to the Session
1063 session().addReference(*this);
1066 KeychainDbCommon::~KeychainDbCommon()
1068 secdebug("KCdb", "DbCommon %p destroyed", this);
1070 // explicitly unschedule ourselves
1071 Server::active().clearTimer(this);
1074 KeychainDbGlobal
&KeychainDbCommon::global() const
1076 return parent
<KeychainDbGlobal
>();
1080 void KeychainDbCommon::select()
1083 void KeychainDbCommon::unselect()
1088 void KeychainDbCommon::makeNewSecrets()
1090 // we already have a master key (right?)
1091 assert(hasMaster());
1093 // tell crypto core to generate the use keys
1094 DatabaseCryptoCore::generateNewSecrets();
1096 // we're now officially "unlocked"; set the timer
1102 // All unlocking activity ultimately funnels through this method.
1103 // This unlocks a DbCommon using the secrets setup in its crypto core
1104 // component, and performs all the housekeeping needed to represent
1105 // the state change.
1106 // Returns true if unlock was successful, false if it failed due to
1107 // invalid/insufficient secrets. Throws on other errors.
1109 bool KeychainDbCommon::unlockDb(DbBlob
*blob
, void **privateAclBlob
)
1112 // Tell the cryptocore to (try to) decode itself. This will fail
1113 // in an astonishing variety of ways if the passphrase is wrong.
1114 assert(hasMaster());
1115 decodeCore(blob
, privateAclBlob
);
1116 secdebug("KCdb", "%p unlock successful", this);
1118 secdebug("KCdb", "%p unlock failed", this);
1122 // get the database parameters only if we haven't got them yet
1123 if (!mValidParams
) {
1124 mParams
= blob
->params
;
1125 n2hi(mParams
.idleTimeout
);
1126 mValidParams
= true; // sticky
1129 bool isLocked
= mIsLocked
;
1131 setUnlocked(); // mark unlocked
1134 // broadcast unlock notification, but only if we were previously locked
1135 notify(kNotificationEventUnlocked
);
1140 void KeychainDbCommon::setUnlocked()
1142 session().addReference(*this); // active/held
1143 mIsLocked
= false; // mark unlocked
1144 activity(); // set timeout timer
1148 void KeychainDbCommon::lockDb()
1150 StLock
<Mutex
> _(*this);
1152 secdebug("KCdb", "common %s(%p) locking", dbName(), this);
1153 DatabaseCryptoCore::invalidate();
1154 notify(kNotificationEventLocked
);
1155 Server::active().clearTimer(this);
1157 mIsLocked
= true; // mark locked
1159 // this call may destroy us if we have no databases anymore
1160 session().removeReference(*this);
1165 DbBlob
*KeychainDbCommon::encode(KeychainDatabase
&db
)
1167 assert(!isLocked()); // must have been unlocked by caller
1169 // export database ACL to blob form
1170 CssmData pubAcl
, privAcl
;
1171 db
.acl().exportBlob(pubAcl
, privAcl
);
1173 // tell the cryptocore to form the blob
1175 form
.randomSignature
= identifier();
1176 form
.sequence
= sequence
;
1177 form
.params
= mParams
;
1178 h2ni(form
.params
.idleTimeout
);
1180 assert(hasMaster());
1181 DbBlob
*blob
= encodeCore(form
, pubAcl
, privAcl
);
1184 db
.acl().allocator
.free(pubAcl
);
1185 db
.acl().allocator
.free(privAcl
);
1191 // Perform deferred lock processing for a database.
1193 void KeychainDbCommon::action()
1195 secdebug("KCdb", "common %s(%p) locked by timer", dbName(), this);
1199 void KeychainDbCommon::activity()
1202 secdebug("KCdb", "setting DbCommon %p timer to %d",
1203 this, int(mParams
.idleTimeout
));
1204 Server::active().setTimer(this, Time::Interval(int(mParams
.idleTimeout
)));
1208 void KeychainDbCommon::sleepProcessing()
1210 secdebug("KCdb", "common %s(%p) sleep-lock processing", dbName(), this);
1211 StLock
<Mutex
> _(*this);
1212 if (mParams
.lockOnSleep
)
1216 void KeychainDbCommon::lockProcessing()
1223 // Keychain global objects
1225 KeychainDbGlobal::KeychainDbGlobal(const DbIdentifier
&id
)
1230 KeychainDbGlobal::~KeychainDbGlobal()
1232 secdebug("KCdb", "DbGlobal %p destroyed", this);