2  * Copyright (c) 2000-2009,2012-2014 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_cdsa_utilities/acl_any.h>    // for default owner ACLs 
  48 #include <security_cdsa_utilities/cssmendian.h> 
  49 #include <security_cdsa_client/wrapkey.h> 
  50 #include <security_cdsa_client/genkey.h> 
  51 #include <security_cdsa_client/signclient.h> 
  52 #include <security_cdsa_client/cryptoclient.h> 
  53 #include <security_cdsa_client/macclient.h> 
  54 #include <securityd_client/dictionary.h> 
  55 #include <security_utilities/endian.h> 
  56 #include "securityd_service/securityd_service/securityd_service_client.h" 
  57 #include <AssertMacros.h> 
  59 #include <sys/sysctl.h> 
  60 #include <sys/kauth.h> 
  63 void unflattenKey(const CssmData 
&flatKey
, CssmKey 
&rawKey
);    //>> make static method on KeychainDatabase 
  68 KeychainDbCommon::CommonSet 
KeychainDbCommon::mCommonSet
; 
  69 ReadWriteLock 
KeychainDbCommon::mRWCommonLock
; 
  71 // Process is using a cached effective uid, login window switches uid after the intial connection 
  72 static void get_process_euid(pid_t pid
, uid_t 
* out_euid
) 
  74     if (!out_euid
) return; 
  76     struct kinfo_proc proc_info 
= {}; 
  77     int mib
[] = {CTL_KERN
, KERN_PROC
, KERN_PROC_PID
, pid
}; 
  78     size_t len 
= sizeof(struct kinfo_proc
); 
  80     ret 
= sysctl(mib
, (sizeof(mib
)/sizeof(int)), &proc_info
, &len
, NULL
, 0); 
  83     if ((ret 
== 0) && (proc_info
.kp_eproc
.e_ucred
.cr_uid 
!= 0)) { 
  84         *out_euid 
= proc_info
.kp_eproc
.e_ucred
.cr_uid
; 
  89 unlock_keybag(KeychainDatabase 
& db
, const void * secret
, int secret_len
) 
  93     if (!db
.common().isLoginKeychain()) return 0; 
  95     service_context_t context 
= db
.common().session().get_current_service_context(); 
  97     // login window attempts to change the password before a session has a uid 
  98     if (context
.s_uid 
== AU_DEFAUDITID
) { 
  99         get_process_euid(db
.process().pid(), &context
.s_uid
); 
 102     // try to unlock first if not found then load/create or unlock 
 103     // loading should happen when the kb common object is created 
 104     // if it doesn't exist yet then the unlock will fail and we'll create everything 
 105     rc 
= service_client_kb_unlock(&context
, secret
, secret_len
); 
 106     if (rc 
== KB_BagNotLoaded
) { 
 107         if (service_client_kb_load(&context
) == KB_BagNotFound
) { 
 108             rc 
= service_client_kb_create(&context
, secret
, secret_len
); 
 110             rc 
= service_client_kb_unlock(&context
, secret
, secret_len
); 
 114     if (rc 
!= 0) { // if we just upgraded make sure we swap the encryption key to the password 
 115         if (!db
.common().session().keybagGetState(session_keybag_check_master_key
)) { 
 116             CssmAutoData 
encKey(Allocator::standard(Allocator::sensitive
)); 
 117             db
.common().get_encryption_key(encKey
); 
 118             if ((rc 
= service_client_kb_unlock(&context
, encKey
.data(), (int)encKey
.length())) == 0) { 
 119                 rc 
= service_client_kb_change_secret(&context
, encKey
.data(), (int)encKey
.length(), secret
, secret_len
); 
 122             if (rc 
!= 0) { // if a login.keychain password exists but doesnt on the keybag update it 
 124                 if ((secret_len 
> 0) && service_client_kb_is_locked(&context
, NULL
, &no_pin
) == 0) { 
 126                         syslog(LOG_ERR
, "Updating iCloud keychain passphrase for uid %d", context
.s_uid
); 
 127                         service_client_kb_change_secret(&context
, NULL
, 0, secret
, secret_len
); 
 131         } // session_keybag_check_master_key 
 135         db
.common().session().keybagSetState(session_keybag_unlocked
|session_keybag_loaded
|session_keybag_check_master_key
); 
 137         syslog(LOG_ERR
, "Failed to unlock iCloud keychain for uid %d", context
.s_uid
); 
 144 change_secret_on_keybag(KeychainDatabase 
& db
, const void * secret
, int secret_len
, const void * new_secret
, int new_secret_len
) 
 146     if (!db
.common().isLoginKeychain()) return; 
 148     service_context_t context 
= db
.common().session().get_current_service_context(); 
 150     // login window attempts to change the password before a session has a uid 
 151     if (context
.s_uid 
== AU_DEFAUDITID
) { 
 152         get_process_euid(db
.process().pid(), &context
.s_uid
); 
 155     // if a login.keychain doesn't exist yet it comes into securityd as a create then change_secret 
 156     // we need to create the keybag in this case if it doesn't exist 
 157     int rc 
= service_client_kb_change_secret(&context
, secret
, secret_len
, new_secret
, new_secret_len
); 
 158     if (rc 
== KB_BagNotLoaded
) { 
 159         if (service_client_kb_load(&context
) == KB_BagNotFound
) { 
 160             rc 
= service_client_kb_create(&context
, new_secret
, new_secret_len
); 
 162             rc 
= service_client_kb_change_secret(&context
, secret
, secret_len
, new_secret
, new_secret_len
); 
 166     // this makes it possible to restore a deleted keybag on condition it still exists in kernel 
 167     if (rc 
!= KB_Success
) { 
 168         service_client_kb_save(&context
); 
 171     // if for some reason we are locked lets unlock so later we don't try and throw up SecurityAgent dialog 
 173     if ((service_client_kb_is_locked(&context
, &locked
, NULL
) == KB_Success
) && locked
) { 
 174         rc 
= service_client_kb_unlock(&context
, new_secret
, new_secret_len
); 
 175         if (rc 
!= KB_Success
) { 
 176             syslog(LOG_ERR
, "Failed to unlock iCloud keychain for uid %d (%d)", context
.s_uid
, (int)rc
); 
 181 // Attempt to unlock the keybag with a AccessCredentials password. 
 182 // Honors UI disabled flags from clients set in the cred before prompt. 
 184 unlock_keybag_with_cred(KeychainDatabase 
&db
, const AccessCredentials 
*cred
){ 
 185     list
<CssmSample
> samples
; 
 186     if (cred 
&& cred
->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK
, samples
)) { 
 187         for (list
<CssmSample
>::iterator it 
= samples
.begin(); it 
!= samples
.end(); it
++) { 
 188             TypedList 
&sample 
= *it
; 
 189             sample
.checkProper(); 
 190             switch (sample
.type()) { 
 191                 // interactively prompt the user - no additional data 
 192                 case CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT
: { 
 193                     StSyncLock
<Mutex
, Mutex
> uisync(db
.common().uiLock(), db
.common()); 
 194                     // Once we get the ui lock, check whether another thread has already unlocked keybag 
 196                     service_context_t context 
= db
.common().session().get_current_service_context(); 
 197                     if ((service_client_kb_is_locked(&context
, &locked
, NULL
) == 0) && locked
) { 
 198                         QueryKeybagPassphrase 
keybagQuery(db
.common().session(), 3); 
 199                         keybagQuery
.inferHints(Server::process()); 
 200                         if (keybagQuery
.query() == SecurityAgent::noReason
) { 
 205                         // another thread already unlocked the keybag 
 210                 // try to use an explicitly given passphrase - Data:passphrase 
 211                 case CSSM_SAMPLE_TYPE_PASSWORD
: { 
 212                     if (sample
.length() != 2) 
 213                         CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
); 
 214                     secinfo("KCdb", "attempting passphrase unlock of keybag"); 
 215                     if (unlock_keybag(db
, sample
[1].data().data(), (int)sample
[1].data().length())) { 
 221                     // Unknown sub-sample for unlocking. 
 222                     secinfo("KCdb", "keybag: unknown sub-sample unlock (%d) ignored", sample
.type()); 
 232 // Create a Database object from initial parameters (create operation) 
 234 KeychainDatabase::KeychainDatabase(const DLDbIdentifier 
&id
, const DBParameters 
¶ms
, Process 
&proc
, 
 235             const AccessCredentials 
*cred
, const AclEntryPrototype 
*owner
) 
 236     : LocalDatabase(proc
), mValidData(false), mSecret(Allocator::standard(Allocator::sensitive
)), mSaveSecret(false), version(0), mBlob(NULL
), mRecoded(false) 
 238     // save a copy of the credentials for later access control 
 239     mCred 
= DataWalkers::copy(cred
, Allocator::standard()); 
 241     // create a new random signature to complete the DLDbIdentifier 
 242     DbBlob::Signature newSig
; 
 243     Server::active().random(newSig
.bytes
); 
 244     DbIdentifier 
ident(id
, newSig
); 
 246     // create common block and initialize 
 247     // Since this is a creation step, figure out the correct blob version for this database 
 248     RefPointer
<KeychainDbCommon
> newCommon 
= new KeychainDbCommon(proc
.session(), ident
, CommonBlob::getCurrentVersionForDb(ident
.dbName())); 
 249     newCommon
->initializeKeybag(); 
 251         StLock
<Mutex
> _(*newCommon
); 
 254         // new common is now visible (in ident-map) but we hold its lock 
 256         // establish the new master secret 
 257         establishNewSecrets(cred
, SecurityAgent::newDatabase
); 
 259         // set initial database parameters 
 260         common().mParams 
= params
; 
 262         // the common is "unlocked" now 
 263         common().makeNewSecrets(); 
 265         // establish initial ACL 
 267                 acl().cssmSetInitial(*owner
); 
 269                 acl().cssmSetInitial(new AnyAclSubject()); 
 272     // for now, create the blob immediately 
 275         proc
.addReference(*this); 
 277         // this new keychain is unlocked; make it so 
 280     secinfo("KCdb", "creating keychain %p %s with common %p", this, (char*)this->dbName(), &common()); 
 285 // Create a Database object from a database blob (decoding) 
 287 KeychainDatabase::KeychainDatabase(const DLDbIdentifier 
&id
, const DbBlob 
*blob
, Process 
&proc
, 
 288     const AccessCredentials 
*cred
) 
 289         : LocalDatabase(proc
), mValidData(false), mSecret(Allocator::standard(Allocator::sensitive
)), mSaveSecret(false), version(0), mBlob(NULL
), mRecoded(false) 
 293     // save a copy of the credentials for later access control 
 294     mCred 
= DataWalkers::copy(cred
, Allocator::standard()); 
 295     mBlob 
= blob
->copy(); 
 297     // check to see if we already know about this database 
 298     DbIdentifier 
ident(id
, blob
->randomSignature
); 
 299         Session 
&session 
= process().session(); 
 300         RefPointer
<KeychainDbCommon
> com
; 
 301     secinfo("kccommon", "looking for a common at %s", ident
.dbName()); 
 302         if (KeychainDbCommon::find(ident
, session
, com
)) { 
 304         secinfo("KCdb", "joining keychain %p %s with common %p", this, (char*)this->dbName(), &common()); 
 306                 // DbCommon not present; make a new one 
 307         secinfo("kccommon", "no common found"); 
 309                 common().mParams 
= blob
->params
; 
 310         secinfo("KCdb", "making keychain %p %s with common %p", this, (char*)this->dbName(), &common()); 
 311                 // this DbCommon is locked; no timer or reference setting 
 313         proc
.addReference(*this); 
 316 void KeychainDbCommon::insert() 
 318     StReadWriteLock 
_(mRWCommonLock
, StReadWriteLock::Write
); 
 322 void KeychainDbCommon::insertHoldingLock() 
 324     mCommonSet
.insert(this); 
 329 // find or make a DbCommon. Returns true if an existing one was found and used. 
 330 bool KeychainDbCommon::find(const DbIdentifier 
&ident
, Session 
&session
, RefPointer
<KeychainDbCommon
> &common
, uint32 requestedVersion
, KeychainDbCommon
* cloneFrom
) 
 332     // Prepare to drop the mRWCommonLock. 
 334         StReadWriteLock 
_(mRWCommonLock
, StReadWriteLock::Read
); 
 335         for (CommonSet::const_iterator it 
= mCommonSet
.begin(); it 
!= mCommonSet
.end(); ++it
) { 
 336             if (&session 
== &(*it
)->session() && ident 
== (*it
)->identifier()) { 
 338                 secinfo("kccommon", "found a common for %s at %p", ident
.dbName(), common
.get()); 
 344     // not found. Grab the write lock, ensure that nobody has beaten us to adding, 
 345     // and then create a DbCommon and add it to the map. 
 347         StReadWriteLock 
_(mRWCommonLock
, StReadWriteLock::Write
); 
 348         for (CommonSet::const_iterator it 
= mCommonSet
.begin(); it 
!= mCommonSet
.end(); ++it
) { 
 349             if (&session 
== &(*it
)->session() && ident 
== (*it
)->identifier()) { 
 351                 secinfo("kccommon", "found a common for %s at %p", ident
.dbName(), common
.get()); 
 358             common 
= new KeychainDbCommon(session
, ident
, *cloneFrom
); 
 359         } else if(requestedVersion 
!= CommonBlob::version_none
) { 
 360             common 
= new KeychainDbCommon(session
, ident
, requestedVersion
); 
 362             common 
= new KeychainDbCommon(session
, ident
); 
 365         secinfo("kccommon", "made a new common for %s at %p", ident
.dbName(), common
.get()); 
 367         // Can't call insert() here, because it grabs the write lock (which we have). 
 368         common
->insertHoldingLock(); 
 370     common
->initializeKeybag(); 
 376 // Special-purpose constructor for keychain synchronization.  Copies an 
 377 // existing keychain but uses the operational keys from secretsBlob.  The  
 378 // new KeychainDatabase will silently replace the existing KeychainDatabase 
 379 // as soon as the client declares that re-encoding of all keychain items is 
 380 // finished.  This is a little perilous since it allows a client to dictate 
 381 // securityd state, but we try to ensure that only the client that started  
 382 // the re-encoding can declare it done.   
 384 KeychainDatabase::KeychainDatabase(KeychainDatabase 
&src
, Process 
&proc
, DbHandle dbToClone
) 
 385         : LocalDatabase(proc
), mValidData(false), mSecret(Allocator::standard(Allocator::sensitive
)), mSaveSecret(false), version(0), mBlob(NULL
), mRecoded(false) 
 387         mCred 
= DataWalkers::copy(src
.mCred
, Allocator::standard()); 
 389         // Give this KeychainDatabase a temporary name 
 390         std::string newDbName 
= std::string("////") + std::string(src
.identifier().dbName()); 
 391         DLDbIdentifier 
newDLDbIdent(src
.identifier().dlDbIdentifier().ssuid(), newDbName
.c_str(), src
.identifier().dlDbIdentifier().dbLocation()); 
 392         DbIdentifier 
ident(newDLDbIdent
, src
.identifier()); 
 394     // create common block and initialize 
 395         RefPointer
<KeychainDbCommon
> newCommon 
= new KeychainDbCommon(proc
.session(), ident
); 
 396     newCommon
->initializeKeybag(); 
 397         StLock
<Mutex
> _(*newCommon
); 
 401         // set initial database parameters from the source keychain 
 402         common().mParams 
= src
.common().mParams
; 
 404         // establish the source keychain's master secret as ours 
 405         // @@@  NB: this is a v. 0.1 assumption.  We *should* trigger new UI  
 406         //      that offers the user the option of using the existing password  
 407         //      or choosing a new one.  That would require a new  
 408         //      SecurityAgentQuery type, new UI, and--possibly--modifications to 
 409         //      ensure that the new password is available here to generate the  
 410         //      new master secret.   
 411         src
.unlockDb(false);            // precaution for masterKey() 
 412         common().setup(src
.blob(), src
.common().masterKey()); 
 414     // import the operational secrets 
 415         RefPointer
<KeychainDatabase
> srcKC 
= Server::keychain(dbToClone
); 
 416         common().importSecrets(srcKC
->common()); 
 418         // import source keychain's ACL   
 419         CssmData pubAcl
, privAcl
; 
 420         src
.acl().exportBlob(pubAcl
, privAcl
); 
 421         importBlob(pubAcl
.data(), privAcl
.data()); 
 422         src
.acl().allocator
.free(pubAcl
); 
 423         src
.acl().allocator
.free(privAcl
); 
 425         // indicate that this keychain should be allowed to do some otherwise 
 426         // risky things required for copying, like re-encoding keys 
 427         mRecodingSource 
= &src
; 
 429         common().setUnlocked(); 
 434         proc
.addReference(*this); 
 435         secinfo("SSdb", "database %s(%p) created as copy, common at %p", 
 436                          common().dbName(), this, &common()); 
 439 // Make a new KeychainDatabase from an old one, but have a completely different location 
 440 KeychainDatabase::KeychainDatabase(const DLDbIdentifier
& id
, KeychainDatabase 
&src
, Process 
&proc
) 
 441 : LocalDatabase(proc
), mValidData(false), mSecret(Allocator::standard(Allocator::sensitive
)), mSaveSecret(false), version(0), mBlob(NULL
), mRecoded(false) 
 443     mCred 
= DataWalkers::copy(src
.mCred
, Allocator::standard()); 
 445     DbIdentifier 
ident(id
, src
.identifier()); 
 447     // create common block and initialize 
 448     RefPointer
<KeychainDbCommon
> newCommon
; 
 449     if(KeychainDbCommon::find(ident
, process().session(), newCommon
, CommonBlob::version_none
, &src
.common())) { 
 450         // A common already existed. Write over it, but note that everything may go horribly from here on out. 
 451         secinfo("kccommon", "Found common where we didn't expect. Possible strange behavior ahead."); 
 452         newCommon
->cloneFrom(src
.common()); 
 455     StLock
<Mutex
> _(*newCommon
); 
 458     // set initial database parameters from the source keychain 
 459     common().mParams 
= src
.common().mParams
; 
 461     // import source keychain's ACL 
 462     CssmData pubAcl
, privAcl
; 
 463     src
.acl().exportBlob(pubAcl
, privAcl
); 
 464     importBlob(pubAcl
.data(), privAcl
.data()); 
 465     src
.acl().allocator
.free(pubAcl
); 
 466     src
.acl().allocator
.free(privAcl
); 
 468     // Copy the source database's blob, if possible 
 470         mBlob 
= src
.mBlob
->copy(); 
 471         version 
= src
.version
; 
 474     // We've copied everything we can from our source. If they were valid, so are we. 
 475     mValidData 
= src
.mValidData
; 
 477     proc
.addReference(*this); 
 478     secinfo("SSdb", "database %s(%p) created as expected clone, common at %p", common().dbName(), this, &common()); 
 482 // Make a new KeychainDatabase from an old one, but have entirely new operational secrets 
 483 KeychainDatabase::KeychainDatabase(uint32 requestedVersion
, KeychainDatabase 
&src
, Process 
&proc
) 
 484 : LocalDatabase(proc
), mValidData(false), mSecret(Allocator::standard(Allocator::sensitive
)), mSaveSecret(false), version(0), mBlob(NULL
), mRecoded(false) 
 486     mCred 
= DataWalkers::copy(src
.mCred
, Allocator::standard()); 
 488     // Give this KeychainDatabase a temporary name 
 489     // this must canonicalize to a different path than the original DB, otherwise another process opening the existing DB wil find this new KeychainDbCommon 
 490     // and call decodeCore with the old blob, overwriting the new secrets and wreaking havoc 
 491     std::string newDbName 
= std::string("////") + std::string(src
.identifier().dbName()) + std::string("_com.apple.security.keychain.migrating"); 
 492     DLDbIdentifier 
newDLDbIdent(src
.identifier().dlDbIdentifier().ssuid(), newDbName
.c_str(), src
.identifier().dlDbIdentifier().dbLocation()); 
 493     DbIdentifier 
ident(newDLDbIdent
, src
.identifier()); 
 495     // hold the lock for src's common during this operation (to match locking common locking order with KeychainDatabase::recodeKey) 
 496     StLock
<Mutex
> __(src
.common()); 
 498     // create common block and initialize 
 499     RefPointer
<KeychainDbCommon
> newCommon
; 
 500     if(KeychainDbCommon::find(ident
, process().session(), newCommon
, requestedVersion
)) { 
 501         // A common already existed here. Write over it, but note that everything may go horribly from here on out. 
 502         secinfo("kccommon", "Found common where we didn't expect. Possible strange behavior ahead."); 
 503         newCommon
->cloneFrom(src
.common(), requestedVersion
); 
 505     newCommon
->initializeKeybag(); 
 506     StLock
<Mutex
> _(*newCommon
); 
 509     // We want to re-use the master secrets from the source database (and so the 
 510     // same password), but reroll new operational secrets. 
 512     // Copy the master secret over... 
 513     src
.unlockDb(false); // precaution 
 515     common().setup(src
.blob(), src
.common().masterKey(), false); // keep the new common's version intact 
 517     // set initial database parameters from the source keychain 
 518     common().mParams 
= src
.common().mParams
; 
 520     // and make new operational secrets 
 521     common().makeNewSecrets(); 
 523     // import source keychain's ACL 
 524     CssmData pubAcl
, privAcl
; 
 525     src
.acl().exportBlob(pubAcl
, privAcl
); 
 526     importBlob(pubAcl
.data(), privAcl
.data()); 
 527     src
.acl().allocator
.free(pubAcl
); 
 528     src
.acl().allocator
.free(privAcl
); 
 530     // indicate that this keychain should be allowed to do some otherwise 
 531     // risky things required for copying, like re-encoding keys 
 532     mRecodingSource 
= &src
; 
 534     common().setUnlocked(); 
 539     proc
.addReference(*this); 
 540     secinfo("SSdb", "database %s(%p) created as expected copy, common at %p", 
 541              common().dbName(), this, &common()); 
 545 // Destroy a Database 
 547 KeychainDatabase::~KeychainDatabase() 
 549     secinfo("KCdb", "deleting database %s(%p) common %p", 
 550         common().dbName(), this, &common()); 
 551     Allocator::standard().free(mCred
); 
 552         Allocator::standard().free(mBlob
); 
 557 // Basic Database virtual implementations 
 559 KeychainDbCommon 
&KeychainDatabase::common() const 
 561         return parent
<KeychainDbCommon
>(); 
 564 const char *KeychainDatabase::dbName() const 
 566         return common().dbName(); 
 569 bool KeychainDatabase::transient() const 
 571         return false;   // has permanent store 
 574 AclKind 
KeychainDatabase::aclKind() const 
 579 Database 
*KeychainDatabase::relatedDatabase() 
 585 // (Re-)Authenticate the database. This changes the stored credentials. 
 587 void KeychainDatabase::authenticate(CSSM_DB_ACCESS_TYPE mode
, 
 588         const AccessCredentials 
*cred
) 
 590         StLock
<Mutex
> _(common()); 
 592         // the (Apple specific) RESET bit means "lock the database now" 
 594         case CSSM_DB_ACCESS_RESET
: 
 595                 secinfo("KCdb", "%p ACCESS_RESET triggers keychain lock", this); 
 599                 //  store the new credentials for future use 
 600                 secinfo("KCdb", "%p authenticate stores new database credentials", this); 
 601                 AccessCredentials 
*newCred 
= DataWalkers::copy(cred
, Allocator::standard()); 
 602                 Allocator::standard().free(mCred
); 
 609 // Make a new KeychainKey. 
 610 // If PERMANENT is off, make a temporary key instead. 
 611 // The db argument allows you to create for another KeychainDatabase (only); 
 612 // it defaults to ourselves. 
 614 RefPointer
<Key
> KeychainDatabase::makeKey(Database 
&db
, const CssmKey 
&newKey
, 
 615         uint32 moreAttributes
, const AclEntryPrototype 
*owner
) 
 618         if (moreAttributes 
& CSSM_KEYATTR_PERMANENT
) 
 619                 return new KeychainKey(db
, newKey
, moreAttributes
, owner
); 
 621                 return process().makeTemporaryKey(newKey
, moreAttributes
, owner
); 
 624 RefPointer
<Key
> KeychainDatabase::makeKey(const CssmKey 
&newKey
, 
 625         uint32 moreAttributes
, const AclEntryPrototype 
*owner
) 
 627         return makeKey(*this, newKey
, moreAttributes
, owner
); 
 632 // Return the database blob, recalculating it as needed. 
 634 DbBlob 
*KeychainDatabase::blob() 
 636         StLock
<Mutex
> _(common()); 
 638         makeUnlocked(false);    // unlock to get master secret 
 639                 encode();                               // (re)encode blob if needed 
 641     activity();                                 // reset timeout 
 642         assert(validBlob());            // better have a valid blob now... 
 648 // Encode the current database as a blob. 
 649 // Note that this returns memory we own and keep. 
 650 // Caller must hold common lock. 
 652 void KeychainDatabase::encode() 
 654         DbBlob 
*blob 
= common().encode(*this); 
 655         Allocator::standard().free(mBlob
); 
 657         version 
= common().version
; 
 658         secinfo("KCdb", "encoded database %p common %p(%s) version %u params=(%u,%u)", 
 659                 this, &common(), dbName(), version
, 
 660                 common().mParams
.idleTimeout
, common().mParams
.lockOnSleep
); 
 665 // Change the passphrase on a database 
 667 void KeychainDatabase::changePassphrase(const AccessCredentials 
*cred
) 
 669         // get and hold the common lock (don't let other threads break in here) 
 670         StLock
<Mutex
> _(common()); 
 672         // establish OLD secret - i.e. unlock the database 
 673         //@@@ do we want to leave the final lock state alone? 
 674     if (common().isLoginKeychain()) mSaveSecret 
= true; 
 675         makeUnlocked(cred
, false); 
 677     // establish NEW secret 
 678     if(!establishNewSecrets(cred
, SecurityAgent::changePassphrase
)) { 
 679         secinfo("KCdb", "Old and new passphrases are the same. Database %s(%p) master secret did not change.", 
 680                  common().dbName(), this); 
 683     if (mSecret
) { mSecret
.reset(); } 
 685         common().invalidateBlob();      // blob state changed 
 686         secinfo("KCdb", "Database %s(%p) master secret changed", common().dbName(), this); 
 687         encode();                       // force rebuild of local blob 
 689         // send out a notification 
 690         notify(kNotificationEventPassphraseChanged
); 
 692     // I guess this counts as an activity 
 697 // Second stage of keychain synchronization: overwrite the original keychain's 
 698 // (this KeychainDatabase's) operational secrets 
 700 void KeychainDatabase::commitSecretsForSync(KeychainDatabase 
&cloneDb
) 
 702     StLock
<Mutex
> _(common()); 
 704         // try to detect spoofing 
 705         if (cloneDb
.mRecodingSource 
!= this)  
 706         CssmError::throwMe(CSSM_ERRCODE_INVALID_DB_HANDLE
); 
 708     // in case we autolocked since starting the sync 
 709     makeUnlocked(false); // call this because we already own the lock 
 710         cloneDb
.unlockDb(false); // we may not own the lock here, so calling unlockDb will lock the cloneDb's common lock 
 712     // Decode all keys whose handles refer to this on-disk keychain so that 
 713     // if the holding client commits the key back to disk, it's encoded with 
 714     // the new operational secrets.  The recoding client *must* hold a write 
 715     // lock for the on-disk keychain from the moment it starts recoding key 
 716     // items until after this call.   
 718         // @@@  This specific implementation is a workaround for 4003540.   
 719         std::vector
<U32HandleObject::Handle
> handleList
; 
 720         U32HandleObject::findAllRefs
<KeychainKey
>(handleList
); 
 721     size_t count 
= handleList
.size(); 
 723         for (unsigned int n 
= 0; n 
< count
; ++n
) { 
 724             RefPointer
<KeychainKey
> kckey 
=  
 725                 U32HandleObject::findRefAndLock
<KeychainKey
>(handleList
[n
], CSSMERR_CSP_INVALID_KEY_REFERENCE
); 
 726             StLock
<Mutex
> _(*kckey
/*, true*/); 
 727             if (kckey
->database().global().identifier() == identifier()) { 
 728                 kckey
->key();               // force decode 
 729                 kckey
->invalidateBlob(); 
 730                                 secinfo("kcrecode", "changed extant key %p (proc %d)", 
 731                                                  &*kckey
, kckey
->process().pid()); 
 736     // mark down that we just recoded 
 739     // it is now safe to replace the old op secrets 
 740     common().importSecrets(cloneDb
.common()); 
 741         common().invalidateBlob(); 
 746 // Extract the database master key as a proper Key object. 
 748 RefPointer
<Key
> KeychainDatabase::extractMasterKey(Database 
&db
, 
 749         const AccessCredentials 
*cred
, const AclEntryPrototype 
*owner
, 
 750         uint32 usage
, uint32 attrs
) 
 752         // get and hold common lock 
 753         StLock
<Mutex
> _(common()); 
 755         // force lock to require re-validation of credentials 
 758         // unlock to establish master secret 
 761         // extract the raw cryptographic key 
 762         CssmClient::WrapKey 
wrap(Server::csp(), CSSM_ALGID_NONE
); 
 764         wrap(common().masterKey(), key
); 
 766         // make the key object and return it 
 767         return makeKey(db
, key
, attrs 
& LocalKey::managedAttributes
, owner
); 
 772 // Unlock this database (if needed) by obtaining the master secret in some 
 773 // suitable way and then proceeding to unlock with it. 
 774 // Does absolutely nothing if the database is already unlocked. 
 775 // The makeUnlocked forms are identical except the assume the caller already 
 776 // holds the common lock. 
 778 void KeychainDatabase::unlockDb(bool unlockKeybag
) 
 780         StLock
<Mutex
> _(common()); 
 781         makeUnlocked(unlockKeybag
); 
 784 void KeychainDatabase::makeUnlocked(bool unlockKeybag
) 
 786         return makeUnlocked(mCred
, unlockKeybag
); 
 789 void KeychainDatabase::makeUnlocked(const AccessCredentials 
*cred
, bool unlockKeybag
) 
 792                 secnotice("KCdb", "%p(%p) unlocking for makeUnlocked()", this, &common()); 
 793         assert(mBlob 
|| (mValidData 
&& common().hasMaster())); 
 794                 establishOldSecrets(cred
); 
 795                 common().setUnlocked(); // mark unlocked 
 796         if (common().isLoginKeychain()) { 
 797             CssmKey master 
= common().masterKey(); 
 799             CssmClient::WrapKey 
wrap(Server::csp(), CSSM_ALGID_NONE
); 
 800             wrap(master
, rawMaster
); 
 802             service_context_t context 
= common().session().get_current_service_context(); 
 803             service_client_stash_load_key(&context
, rawMaster
.keyData(), (int)rawMaster
.length()); 
 805         } else if (unlockKeybag 
&& common().isLoginKeychain()) { 
 807         service_context_t context 
= common().session().get_current_service_context(); 
 808         if ((service_client_kb_is_locked(&context
, &locked
, NULL
) == 0) && locked
) { 
 809             if (!unlock_keybag_with_cred(*this, cred
)) { 
 810                 syslog(LOG_NOTICE
, "failed to unlock iCloud keychain"); 
 814         if (!mValidData
) {      // need to decode to get our ACLs, master secret available 
 815                 secnotice("KCdb", "%p(%p) is unlocked; decoding for makeUnlocked()", this, &common()); 
 817                         CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
); 
 824 // Invoke the securityd_service to retrieve the keychain master 
 825 // key from the AppleFDEKeyStore. 
 827 void KeychainDatabase::stashDbCheck() 
 829     CssmAutoData 
masterKey(Allocator::standard(Allocator::sensitive
)); 
 830     CssmAutoData 
encKey(Allocator::standard(Allocator::sensitive
)); 
 834     void * stash_key 
= NULL
; 
 835     int stash_key_len 
= 0; 
 836     service_context_t context 
= common().session().get_current_service_context(); 
 837     rc 
= service_client_stash_get_key(&context
, &stash_key
, &stash_key_len
); 
 840             masterKey
.copy(CssmData((void *)stash_key
,stash_key_len
)); 
 841             memset(stash_key
, 0, stash_key_len
); 
 845         CssmError::throwMe(rc
); 
 849         StLock
<Mutex
> _(common()); 
 851         // Now establish it as the keychain master key 
 852         CssmClient::Key 
key(Server::csp(), masterKey
.get()); 
 853         CssmKey::Header 
&hdr 
= key
.header(); 
 854         hdr
.keyClass(CSSM_KEYCLASS_SESSION_KEY
); 
 855         hdr
.algorithm(CSSM_ALGID_3DES_3KEY_EDE
); 
 856         hdr
.usage(CSSM_KEYUSE_ANY
); 
 857         hdr
.blobType(CSSM_KEYBLOB_RAW
); 
 858         hdr
.blobFormat(CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING
); 
 859         common().setup(mBlob
, key
); 
 862             CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
); 
 864         common().get_encryption_key(encKey
); 
 867     // when upgrading from pre-10.9 create a keybag if it doesn't exist with the encryption key 
 868     // only do this after we have verified the master key unlocks the login.keychain 
 869     if (service_client_kb_load(&context
) == KB_BagNotFound
) { 
 870         service_client_kb_create(&context
, encKey
.data(), (int)encKey
.length()); 
 875 // Get the keychain master key and invoke the securityd_service 
 876 // to stash it in the AppleFDEKeyStore ready for commit to the 
 879 void KeychainDatabase::stashDb() 
 881     CssmAutoData 
data(Allocator::standard(Allocator::sensitive
)); 
 884         StLock
<Mutex
> _(common()); 
 886         if (!common().isValid()) { 
 887             CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
); 
 890         CssmKey key 
= common().masterKey(); 
 891         data
.copy(key
.keyData()); 
 894     service_context_t context 
= common().session().get_current_service_context(); 
 895     int rc 
= service_client_stash_set_key(&context
, data
.data(), (int)data
.length()); 
 896     if (rc 
!= 0) CssmError::throwMe(rc
); 
 900 // The following unlock given an explicit passphrase, rather than using 
 901 // (special cred sample based) default procedures. 
 903 void KeychainDatabase::unlockDb(const CssmData 
&passphrase
, bool unlockKeybag
) 
 905         StLock
<Mutex
> _(common()); 
 906         makeUnlocked(passphrase
, unlockKeybag
); 
 909 void KeychainDatabase::makeUnlocked(const CssmData 
&passphrase
, bool unlockKeybag
) 
 912                 if (decode(passphrase
)) 
 915                         CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
); 
 916         } else if (!mValidData
) {       // need to decode to get our ACLs, passphrase available 
 918                         CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
); 
 921     if (unlockKeybag 
&& common().isLoginKeychain()) { 
 923         service_context_t context 
= common().session().get_current_service_context(); 
 924         if (!common().session().keybagGetState(session_keybag_check_master_key
) || ((service_client_kb_is_locked(&context
, &locked
, NULL
) == 0) && locked
)) { 
 925             unlock_keybag(*this, passphrase
.data(), (int)passphrase
.length()); 
 935 // Nonthrowing passphrase-based unlock. This returns false if unlock failed. 
 936 // Note that this requires an explicitly given passphrase. 
 937 // Caller must hold common lock. 
 939 bool KeychainDatabase::decode(const CssmData 
&passphrase
) 
 942         common().setup(mBlob
, passphrase
); 
 943         bool success 
= decode(); 
 944     if (success 
&& common().isLoginKeychain()) { 
 945         unlock_keybag(*this, passphrase
.data(), (int)passphrase
.length()); 
 952 // Given the established master secret, decode the working keys and other 
 953 // functional secrets for this database. Return false (do NOT throw) if 
 954 // the decode fails. Call this in low(er) level code once you established 
 957 bool KeychainDatabase::decode() 
 960         assert(common().hasMaster()); 
 961         void *privateAclBlob
; 
 962         if (common().unlockDb(mBlob
, &privateAclBlob
)) { 
 964                         acl().importBlob(mBlob
->publicAclBlob(), privateAclBlob
); 
 967                 Allocator::standard().free(privateAclBlob
); 
 970         secinfo("KCdb", "%p decode failed", this); 
 976 // Given an AccessCredentials for this database, wring out the existing primary 
 977 // database secret by whatever means necessary. 
 978 // On entry, caller must hold the database common lock. It will be held 
 979 // throughout except when user interaction is required. User interaction  
 980 // requires relinquishing the database common lock and taking the UI lock. On 
 981 // return from user interaction, the UI lock is relinquished and the database 
 982 // common lock must be reacquired. At no time may the caller hold both locks. 
 983 // On exit, the crypto core has its master secret. If things go wrong, 
 984 // we will throw a suitable exception. Note that encountering any malformed 
 985 // credential sample will throw, but this is not guaranteed -- don't assume 
 986 // that NOT throwing means creds is entirely well-formed (it may just be good 
 987 // enough to work THIS time). 
 990 // Walk through the creds. Fish out those credentials (in order) that 
 991 // are for unlock processing (they have no ACL subject correspondents), 
 992 // and (try to) obey each in turn, until one produces a valid secret 
 993 // or you run out. If no special samples are found at all, interpret that as 
 994 // "use the system global default," which happens to be hard-coded right here. 
 996 void KeychainDatabase::establishOldSecrets(const AccessCredentials 
*creds
) 
 998         bool forSystem 
= this->belongsToSystem();       // this keychain belongs to the system security domain 
1000         // attempt system-keychain unlock 
1002                 SystemKeychainKey 
systemKeychain(kSystemUnlockFile
); 
1003                 if (systemKeychain
.matches(mBlob
->randomSignature
)) { 
1004                         secinfo("KCdb", "%p attempting system unlock", this); 
1005                         common().setup(mBlob
, CssmClient::Key(Server::csp(), systemKeychain
.key(), true)); 
1011         list
<CssmSample
> samples
; 
1012         if (creds 
&& creds
->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK
, samples
)) { 
1013                 for (list
<CssmSample
>::iterator it 
= samples
.begin(); it 
!= samples
.end(); it
++) { 
1014                         TypedList 
&sample 
= *it
; 
1015                         sample
.checkProper(); 
1016                         switch (sample
.type()) { 
1017                         // interactively prompt the user - no additional data 
1018                         case CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT
: 
1020                                         if (interactiveUnlock()) 
1024                         // try to use an explicitly given passphrase - Data:passphrase 
1025                         case CSSM_SAMPLE_TYPE_PASSWORD
: 
1026                                 if (sample
.length() != 2) 
1027                                         CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
); 
1028                                 secinfo("KCdb", "%p attempting passphrase unlock", this); 
1029                                 if (decode(sample
[1])) 
1032                         // try to open with a given master key - Data:CSP or KeyHandle, Data:CssmKey 
1033                         case CSSM_SAMPLE_TYPE_SYMMETRIC_KEY
: 
1034                         case CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY
: 
1036                                 secinfo("KCdb", "%p attempting explicit key unlock", this); 
1037                                 common().setup(mBlob
, keyFromCreds(sample
, 4)); 
1042                         // explicitly defeat the default action but don't try anything in particular 
1043                         case CSSM_WORDID_CANCELED
: 
1044                                 secinfo("KCdb", "%p defeat default action", this); 
1047                                 // Unknown sub-sample for unlocking. 
1048                                 // If we wanted to be fascist, we could now do 
1049                                 //  CssmError::throwMe(CSSM_ERRCODE_SAMPLE_VALUE_NOT_SUPPORTED); 
1050                                 // But instead we try to be tolerant and continue on. 
1051                                 // This DOES however count as an explicit attempt at specifying unlock, 
1052                                 // so we will no longer try the default case below... 
1053                                 secinfo("KCdb", "%p unknown sub-sample unlock (%d) ignored", this, sample
.type()); 
1062                         if (interactiveUnlock()) 
1067         // out of options - no secret obtained 
1068         CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
); 
1072 // This function is almost identical to establishOldSecrets, but: 
1073 //   1. It will never prompt the user; these credentials either work or they don't 
1074 //   2. It will not change the secrets of this database 
1076 // TODO: These two functions should probably be refactored to something nicer. 
1077 bool KeychainDatabase::checkCredentials(const AccessCredentials 
*creds
) { 
1079     list
<CssmSample
> samples
; 
1080     if (creds 
&& creds
->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK
, samples
)) { 
1081         for (list
<CssmSample
>::iterator it 
= samples
.begin(); it 
!= samples
.end(); it
++) { 
1082             TypedList 
&sample 
= *it
; 
1083             sample
.checkProper(); 
1084             switch (sample
.type()) { 
1085                 // interactively prompt the user - no additional data 
1086                 case CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT
: 
1087                     // do nothing, because this function will never prompt the user 
1088                     secinfo("integrity", "%p ignoring keychain prompt", this); 
1090                 // try to use an explicitly given passphrase - Data:passphrase 
1091                 case CSSM_SAMPLE_TYPE_PASSWORD
: 
1092                     if (sample
.length() != 2) 
1093                         CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
); 
1094                     secinfo("integrity", "%p checking passphrase", this); 
1095                     if(validatePassphrase(sample
[1])) { 
1099                 // try to open with a given master key - Data:CSP or KeyHandle, Data:CssmKey 
1100                 case CSSM_SAMPLE_TYPE_SYMMETRIC_KEY
: 
1101                 case CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY
: 
1103                     secinfo("integrity", "%p attempting explicit key unlock", this); 
1105                         CssmClient::Key checkKey 
= keyFromCreds(sample
, 4); 
1106                         if(common().validateKey(checkKey
)) { 
1110                         // ignore all problems in keyFromCreds 
1111                         secinfo("integrity", "%p caught error", this); 
1118     // out of options - credentials don't match 
1122 uint32_t KeychainDatabase::interactiveUnlockAttempts 
= 0; 
1124 bool KeychainDatabase::interactiveUnlock() 
1126         secinfo("KCdb", "%p attempting interactive unlock", this); 
1127     interactiveUnlockAttempts
++; 
1129         SecurityAgent::Reason reason 
= SecurityAgent::noReason
; 
1130     QueryUnlock 
query(*this); 
1131         // take UI interlock and release DbCommon lock (to avoid deadlocks) 
1132         StSyncLock
<Mutex
, Mutex
> uisync(common().uiLock(), common()); 
1134         // now that we have the UI lock, interact unless another thread unlocked us first 
1136                 query
.inferHints(Server::process()); 
1138         if (mSaveSecret 
&& reason 
== SecurityAgent::noReason
) { 
1139             query
.retrievePassword(mSecret
); 
1143                 secinfo("KCdb", "%p was unlocked during uiLock delay", this); 
1146     if (common().isLoginKeychain()) { 
1147         bool locked 
= false; 
1148         service_context_t context 
= common().session().get_current_service_context(); 
1149         if ((service_client_kb_is_locked(&context
, &locked
, NULL
) == 0) && locked
) { 
1150             QueryKeybagNewPassphrase 
keybagQuery(common().session()); 
1151             keybagQuery
.inferHints(Server::process()); 
1152             CssmAutoData 
pass(Allocator::standard(Allocator::sensitive
)); 
1153             CssmAutoData 
oldPass(Allocator::standard(Allocator::sensitive
)); 
1154             SecurityAgent::Reason queryReason 
= keybagQuery
.query(oldPass
, pass
); 
1155             if (queryReason 
== SecurityAgent::noReason
) { 
1156                 service_client_kb_change_secret(&context
, oldPass
.data(), (int)oldPass
.length(), pass
.data(), (int)pass
.length()); 
1157             } else if (queryReason 
== SecurityAgent::resettingPassword
) { 
1158                 query
.retrievePassword(pass
); 
1159                 service_client_kb_reset(&context
, pass
.data(), (int)pass
.length()); 
1165     return reason 
== SecurityAgent::noReason
; 
1168 uint32_t KeychainDatabase::getInteractiveUnlockAttempts() { 
1169     if (csr_check(CSR_ALLOW_APPLE_INTERNAL
)) { 
1170         // Not an internal install; don't answer 
1173         return interactiveUnlockAttempts
; 
1179 // Same thing, but obtain a new secret somehow and set it into the common. 
1181 bool KeychainDatabase::establishNewSecrets(const AccessCredentials 
*creds
, SecurityAgent::Reason reason
) 
1183         list
<CssmSample
> samples
; 
1184         if (creds 
&& creds
->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK
, samples
)) { 
1185                 for (list
<CssmSample
>::iterator it 
= samples
.begin(); it 
!= samples
.end(); it
++) { 
1186                         TypedList 
&sample 
= *it
; 
1187                         sample
.checkProper(); 
1188                         switch (sample
.type()) { 
1189                         // interactively prompt the user 
1190                         case CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT
: 
1192                                 secinfo("KCdb", "%p specified interactive passphrase", this); 
1193                                 QueryNewPassphrase 
query(*this, reason
); 
1194                                 StSyncLock
<Mutex
, Mutex
> uisync(common().uiLock(), common()); 
1195                                 query
.inferHints(Server::process()); 
1196                                 CssmAutoData 
passphrase(Allocator::standard(Allocator::sensitive
)); 
1197                 CssmAutoData 
oldPassphrase(Allocator::standard(Allocator::sensitive
)); 
1198                                 if (query(oldPassphrase
, passphrase
) == SecurityAgent::noReason
) { 
1199                                         common().setup(NULL
, passphrase
); 
1200                     change_secret_on_keybag(*this, oldPassphrase
.data(), (int)oldPassphrase
.length(), passphrase
.data(), (int)passphrase
.length()); 
1205                         // try to use an explicitly given passphrase 
1206                         case CSSM_SAMPLE_TYPE_PASSWORD
: 
1208                     secinfo("KCdb", "%p specified explicit passphrase", this); 
1209                     if (sample
.length() != 2) 
1210                         CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
); 
1211                     if (common().isLoginKeychain()) { 
1212                         CssmAutoData 
oldPassphrase(Allocator::standard(Allocator::sensitive
)); 
1213                         list
<CssmSample
> oldSamples
; 
1214                         creds
->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK
, oldSamples
); 
1215                         for (list
<CssmSample
>::iterator oit 
= oldSamples
.begin(); oit 
!= oldSamples
.end(); oit
++) { 
1216                             TypedList 
&tmpList 
= *oit
; 
1217                             tmpList
.checkProper(); 
1218                             if (tmpList
.type() == CSSM_SAMPLE_TYPE_PASSWORD
) { 
1219                                 if (tmpList
.length() == 2) { 
1220                                     oldPassphrase 
= tmpList
[1].data(); 
1224                         if (!oldPassphrase
.length() && mSecret 
&& mSecret
.length()) { 
1225                             oldPassphrase 
= mSecret
; 
1227                         if ((oldPassphrase
.length() == sample
[1].data().length()) && 
1228                             !memcmp(oldPassphrase
.data(), sample
[1].data().data(), oldPassphrase
.length()) && 
1229                             oldPassphrase
.length()) { 
1230                             // don't change master key if the passwords are the same 
1233                         common().setup(NULL
, sample
[1]); 
1234                         change_secret_on_keybag(*this, oldPassphrase
.data(), (int)oldPassphrase
.length(), sample
[1].data().data(), (int)sample
[1].data().length()); 
1237                         common().setup(NULL
, sample
[1]); 
1241                         // try to open with a given master key 
1242                         case CSSM_WORDID_SYMMETRIC_KEY
: 
1243                         case CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY
: 
1244                                 secinfo("KCdb", "%p specified explicit master key", this); 
1245                                 common().setup(NULL
, keyFromCreds(sample
, 3)); 
1247                         // explicitly defeat the default action but don't try anything in particular 
1248                         case CSSM_WORDID_CANCELED
: 
1249                                 secinfo("KCdb", "%p defeat default action", this); 
1252                                 // Unknown sub-sample for acquiring new secret. 
1253                                 // If we wanted to be fascist, we could now do 
1254                                 //  CssmError::throwMe(CSSM_ERRCODE_SAMPLE_VALUE_NOT_SUPPORTED); 
1255                                 // But instead we try to be tolerant and continue on. 
1256                                 // This DOES however count as an explicit attempt at specifying unlock, 
1257                                 // so we will no longer try the default case below... 
1258                                 secinfo("KCdb", "%p unknown sub-sample acquisition (%d) ignored", 
1259                                         this, sample
.type()); 
1264                 // default action -- interactive (only) 
1265                 QueryNewPassphrase 
query(*this, reason
); 
1266                 StSyncLock
<Mutex
, Mutex
> uisync(common().uiLock(), common()); 
1267         query
.inferHints(Server::process()); 
1268                 CssmAutoData 
passphrase(Allocator::standard(Allocator::sensitive
)); 
1269         CssmAutoData 
oldPassphrase(Allocator::standard(Allocator::sensitive
)); 
1270                 if (query(oldPassphrase
, passphrase
) == SecurityAgent::noReason
) { 
1271                         common().setup(NULL
, passphrase
); 
1272             change_secret_on_keybag(*this, oldPassphrase
.data(), (int)oldPassphrase
.length(), passphrase
.data(), (int)passphrase
.length()); 
1277         // out of options - no secret obtained 
1278         CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
); 
1283 // Given a (truncated) Database credentials TypedList specifying a master key, 
1284 // locate the key and return a reference to it. 
1286 CssmClient::Key 
KeychainDatabase::keyFromCreds(const TypedList 
&sample
, unsigned int requiredLength
) 
1288         // decode TypedList structure (sample type; Data:CSPHandle; Data:CSSM_KEY) 
1289         assert(sample
.type() == CSSM_SAMPLE_TYPE_SYMMETRIC_KEY 
|| sample
.type() == CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY
); 
1290         if (sample
.length() != requiredLength
 
1291                 || sample
[1].type() != CSSM_LIST_ELEMENT_DATUM
 
1292                 || sample
[2].type() != CSSM_LIST_ELEMENT_DATUM
 
1293                 || (requiredLength 
== 4 && sample
[3].type() != CSSM_LIST_ELEMENT_DATUM
)) 
1294                         CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
); 
1295         KeyHandle 
&handle 
= *sample
[1].data().interpretedAs
<KeyHandle
>(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
); 
1296     // We used to be able to check the length but supporting multiple client 
1297     // architectures dishes that (sizeof(CSSM_KEY) varies due to alignment and 
1298     // field-size differences).  The decoding in the transition layer should  
1299     // serve as a sufficient garbling check anyway.   
1300     if (sample
[2].data().data() == NULL
) 
1301         CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
); 
1302     CssmKey 
&key 
= *sample
[2].data().interpretedAs
<CssmKey
>(); 
1304         if (key
.header().cspGuid() == gGuidAppleCSPDL
) { 
1305                 // handleOrKey is a SecurityServer KeyHandle; ignore key argument 
1306                 return safer_cast
<LocalKey 
&>(*Server::key(handle
)); 
1308         if (sample
.type() == CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY
) { 
1310                         Contents (see DefaultCredentials::unlockKey in libsecurity_keychain/defaultcreds.cpp) 
1312                         sample[0]       sample type 
1313                         sample[1]       csp handle for master or wrapping key; is really a keyhandle 
1314                         sample[2]       masterKey [not used since securityd cannot interpret; use sample[1] handle instead] 
1315                         sample[3]       UnlockReferralRecord data, in this case the flattened symmetric key 
1318                 // RefPointer<Key> Server::key(KeyHandle key) 
1319                 KeyHandle keyhandle 
= *sample
[1].data().interpretedAs
<KeyHandle
>(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
); 
1320                 CssmData 
&flattenedKey 
= sample
[3].data(); 
1321                 RefPointer
<Key
> unwrappingKey 
= Server::key(keyhandle
); 
1322                 Database 
&db
=unwrappingKey
->database(); 
1324                 CssmKey rawWrappedKey
; 
1325                 unflattenKey(flattenedKey
, rawWrappedKey
); 
1327                 RefPointer
<Key
> masterKey
; 
1328                 CssmData emptyDescriptiveData
; 
1329                 const AccessCredentials 
*cred 
= NULL
; 
1330                 const AclEntryPrototype 
*owner 
= NULL
; 
1331                 CSSM_KEYUSE usage 
= CSSM_KEYUSE_ANY
; 
1332                 CSSM_KEYATTR_FLAGS attrs 
= CSSM_KEYATTR_EXTRACTABLE
;    //CSSM_KEYATTR_RETURN_REF |  
1334                 // Get default credentials for unwrappingKey (the one on the token) 
1335                 // Copied from Statics::Statics() in libsecurity_keychain/aclclient.cpp 
1336                 // Following KeyItem::getCredentials, one sees that the "operation" parameter 
1337                 // e.g. "CSSM_ACL_AUTHORIZATION_DECRYPT" is ignored 
1338                 Allocator 
&alloc 
= Allocator::standard(); 
1339                 AutoCredentials 
promptCred(alloc
, 3);// enable interactive prompting 
1341                 // promptCred: a credential permitting user prompt confirmations 
1343                 //  a KEYCHAIN_PROMPT sample, both by itself and in a THRESHOLD 
1344                 //  a PROMPTED_PASSWORD sample 
1345                 promptCred
.sample(0) = TypedList(alloc
, CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT
); 
1346                 promptCred
.sample(1) = TypedList(alloc
, CSSM_SAMPLE_TYPE_THRESHOLD
, 
1347                         new(alloc
) ListElement(TypedList(alloc
, CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT
))); 
1348                 promptCred
.sample(2) = TypedList(alloc
, CSSM_SAMPLE_TYPE_PROMPTED_PASSWORD
, 
1349                         new(alloc
) ListElement(alloc
, CssmData())); 
1351                 // This unwrap object is here just to provide a context 
1352                 CssmClient::UnwrapKey 
unwrap(Server::csp(), CSSM_ALGID_NONE
);   //ok to lie about csp here 
1353                 unwrap
.mode(CSSM_ALGMODE_NONE
); 
1354                 unwrap
.padding(CSSM_PADDING_PKCS1
); 
1355                 unwrap
.cred(promptCred
); 
1356                 unwrap
.add(CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT
, uint32(CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7
)); 
1357                 Security::Context 
*tmpContext
; 
1358                 CSSM_CC_HANDLE CCHandle 
= unwrap
.handle(); 
1359                 /*CSSM_RETURN rx = */ CSSM_GetContext (CCHandle
, (CSSM_CONTEXT_PTR 
*)&tmpContext
); 
1361                 // OK, this is skanky but necessary. We overwrite fields in the context struct 
1363                 tmpContext
->ContextType 
= CSSM_ALGCLASS_ASYMMETRIC
; 
1364                 tmpContext
->AlgorithmType 
= CSSM_ALGID_RSA
; 
1366                 db
.unwrapKey(*tmpContext
, cred
, owner
, unwrappingKey
, NULL
, usage
, attrs
, 
1367                         rawWrappedKey
, masterKey
, emptyDescriptiveData
); 
1369             Allocator::standard().free(rawWrappedKey
.KeyData
.Data
); 
1371                 return safer_cast
<LocalKey 
&>(*masterKey
).key(); 
1373         else if (sample
.type() == CSSM_SAMPLE_TYPE_SYMMETRIC_KEY 
&& sample
.length() == 4 && sample
[3].data().length() > 0) { 
1375          Contents (see MasterKeyUnlockCredentials in libsecurity_cdsa_client/lib/aclclient.cpp) 
1377          sample[0]  sample type 
1378          sample[1]  0, since we don't have a valid handle 
1379          sample[2]  CssmKey of the masterKey [can't immediately use since it includes a CSSM_DATA struct with pointers] 
1380          sample[3]  flattened symmetric master key, including the key data 
1383         // Fix up key to include actual data 
1384         CssmData 
&flattenedKey 
= sample
[3].data(); 
1385         unflattenKey(flattenedKey
, key
); 
1387         // Check that we have a reasonable key 
1388         if (key
.header().blobType() != CSSM_KEYBLOB_RAW
) { 
1389             CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE
); 
1391         if (key
.header().keyClass() != CSSM_KEYCLASS_SESSION_KEY
) { 
1392             CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS
); 
1395         // bring the key into the CSP and return it 
1396         return CssmClient::Key(Server::csp(), key
, true); 
1398                 // not a KeyHandle reference; use key as a raw key 
1399                 if (key
.header().blobType() != CSSM_KEYBLOB_RAW
) 
1400                         CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE
); 
1401                 if (key
.header().keyClass() != CSSM_KEYCLASS_SESSION_KEY
) 
1402                         CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS
); 
1403                 return CssmClient::Key(Server::csp(), key
, true); 
1407 void unflattenKey(const CssmData 
&flatKey
, CssmKey 
&rawKey
) 
1409     // The format we're expecting is a CSSM_KEY followed by the actual key data: 
1410     //    CSSM_KEY : KEY DATA 
1411     // which is approximately: 
1412     //    h2ni(CSSM_KEYHEADER) : 4 bytes padding : CSSM_DATA{?:?} : KEY BYTES 
1414     // Note that CSSM_KEY includes a CSSM_DATA struct, which we will ignore as it has pointers. 
1415     // The pointer and length will be set to whatever key data follows the CSSM_KEY in rawKey. 
1417         // unflatten the raw input key naively: key header then key data 
1418         // We also convert it back to host byte order 
1419         // A CSSM_KEY is a CSSM_KEYHEADER followed by a CSSM_DATA 
1421         // Now copy: header, then key struct, then key data 
1422         memcpy(&rawKey
.KeyHeader
, flatKey
.Data
, sizeof(CSSM_KEYHEADER
)); 
1423         memcpy(&rawKey
.KeyData
, flatKey
.Data 
+ sizeof(CSSM_KEYHEADER
), sizeof(CSSM_DATA
)); 
1424         size_t keyDataLength 
= flatKey
.length() - sizeof(CSSM_KEY
); 
1425         rawKey
.KeyData
.Data 
= Allocator::standard().malloc
<uint8
>(keyDataLength
); 
1426         rawKey
.KeyData
.Length 
= keyDataLength
; 
1427         memcpy(rawKey
.KeyData
.Data
, flatKey
.Data 
+ sizeof(CSSM_KEY
), keyDataLength
); 
1428         Security::n2hi(rawKey
.KeyHeader
);       // convert it to host byte order 
1433 // Verify a putative database passphrase. 
1434 // If the database is already unlocked, just check the passphrase. 
1435 // Otherwise, unlock with that passphrase and report success. 
1436 // Caller must hold the common lock. 
1438 bool KeychainDatabase::validatePassphrase(const CssmData 
&passphrase
) const 
1440         if (common().hasMaster()) { 
1441                 // verify against known secret 
1442                 return common().validatePassphrase(passphrase
); 
1444                 // no master secret - perform "blind" unlock to avoid actual unlock 
1446                         DatabaseCryptoCore test
; 
1447                         test
.setup(mBlob
, passphrase
); 
1448                         test
.decodeCore(mBlob
, NULL
); 
1458 // Lock this database 
1460 void KeychainDatabase::lockDb() 
1467 // Given a Key for this database, encode it into a blob and return it. 
1469 KeyBlob 
*KeychainDatabase::encodeKey(const CssmKey 
&key
, const CssmData 
&pubAcl
, const CssmData 
&privAcl
) 
1471         bool inTheClear 
= false; 
1472         if((key
.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY
) && 
1473            !(key
.attribute(CSSM_KEYATTR_PUBLIC_KEY_ENCRYPT
))) { 
1476         StLock
<Mutex
> _(common()); 
1478                 makeUnlocked(false); 
1480     // tell the cryptocore to form the key blob 
1481     return common().encodeKeyCore(key
, pubAcl
, privAcl
, inTheClear
); 
1486 // Given a "blobbed" key for this database, decode it into its real 
1487 // key object and (re)populate its ACL. 
1489 void KeychainDatabase::decodeKey(KeyBlob 
*blob
, CssmKey 
&key
, void * &pubAcl
, void * &privAcl
) 
1491         StLock
<Mutex
> _(common()); 
1493         if(!blob
->isClearText()) 
1494                 makeUnlocked(false);                                                    // we need our keys 
1496         common().decodeKeyCore(blob
, key
, pubAcl
, privAcl
); 
1497         // memory protocol: pubAcl points into blob; privAcl was allocated 
1503 // Given a KeychainKey (that implicitly belongs to another keychain),  
1504 // return it encoded using this keychain's operational secrets.   
1506 KeyBlob 
*KeychainDatabase::recodeKey(KeychainKey 
&oldKey
) 
1508         if (mRecodingSource 
!= &oldKey
.referent
<KeychainDatabase
>()) { 
1509         CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
); 
1512     // To protect this operation, we need to take the mutex for both our common and the remote key's common in some defined order. 
1513     // Grab the common being cloned (oldKey's) first, and then the common receiving the recoding (ours). 
1514     StLock
<Mutex
> _ (oldKey
.referent
<KeychainDatabase
>().common()); 
1515     StLock
<Mutex
> __(common()); 
1517         oldKey
.instantiateAcl();        // make sure key is decoded 
1518         CssmData publicAcl
, privateAcl
; 
1519         oldKey
.exportBlob(publicAcl
, privateAcl
); 
1520         // NB: blob's memory belongs to caller, not the common 
1523          * Make sure the new key is in the same cleartext/encrypted state. 
1525         bool inTheClear 
= false; 
1526         assert(oldKey
.blob()); 
1527         if(oldKey
.blob() && oldKey
.blob()->isClearText()) { 
1531         KeyBlob 
*blob 
= common().encodeKeyCore(oldKey
.cssmKey(), publicAcl
, privateAcl
, inTheClear
); 
1532         oldKey
.acl().allocator
.free(publicAcl
); 
1533         oldKey
.acl().allocator
.free(privateAcl
); 
1539 // Modify database parameters 
1541 void KeychainDatabase::setParameters(const DBParameters 
¶ms
) 
1543         StLock
<Mutex
> _(common()); 
1544     makeUnlocked(false); 
1545         common().mParams 
= params
; 
1546     common().invalidateBlob();          // invalidate old blobs 
1547     activity();                         // (also resets the timeout timer) 
1548         secinfo("KCdb", "%p common %p(%s) set params=(%u,%u)", 
1549                 this, &common(), dbName(), params
.idleTimeout
, params
.lockOnSleep
); 
1554 // Retrieve database parameters 
1556 void KeychainDatabase::getParameters(DBParameters 
¶ms
) 
1558         StLock
<Mutex
> _(common()); 
1559     makeUnlocked(false); 
1560         params 
= common().mParams
; 
1561     //activity();               // getting parameters does not reset the idle timer 
1566 // RIGHT NOW, database ACLs are attached to the database. 
1567 // This will soon move upstairs. 
1569 SecurityServerAcl 
&KeychainDatabase::acl() 
1576 // Intercept ACL change requests and reset blob validity 
1578 void KeychainDatabase::instantiateAcl() 
1580         StLock
<Mutex
> _(common()); 
1581         makeUnlocked(false); 
1584 void KeychainDatabase::changedAcl() 
1586         StLock
<Mutex
> _(common()); 
1592 // Check an incoming DbBlob for basic viability 
1594 void KeychainDatabase::validateBlob(const DbBlob 
*blob
) 
1596     // perform basic validation on the blob 
1598         blob
->validate(CSSMERR_APPLEDL_INVALID_DATABASE_BLOB
); 
1599         switch (blob
->version()) { 
1600 #if defined(COMPAT_OSX_10_0) 
1601                 case DbBlob::version_MacOS_10_0
: 
1604                 case DbBlob::version_MacOS_10_1
: 
1606                 case DbBlob::version_partition
: 
1609                         CssmError::throwMe(CSSMERR_APPLEDL_INCOMPATIBLE_DATABASE_BLOB
); 
1614 // Check if this database is currently recoding 
1616 bool KeychainDatabase::isRecoding() 
1618     secnotice("integrity", "recoding source: %p", mRecodingSource
.get()); 
1619     return (mRecodingSource
.get() != NULL 
|| mRecoded
); 
1623 // Mark ourselves as no longer recoding 
1625 void KeychainDatabase::recodeFinished() 
1627     secnotice("integrity", "recoding finished"); 
1628     mRecodingSource 
= NULL
; 
1634 // Debugging support 
1636 #if defined(DEBUGDUMP) 
1638 void KeychainDbCommon::dumpNode() 
1640         PerSession::dumpNode(); 
1641         uint32 sig
; memcpy(&sig
, &mIdentifier
.signature(), sizeof(sig
)); 
1642         Debug::dump(" %s[%8.8x]", mIdentifier
.dbName(), sig
); 
1644                 Debug::dump(" locked"); 
1646                 time_t whenTime 
= time_t(when()); 
1647                 Debug::dump(" unlocked(%24.24s/%.2g)", ctime(&whenTime
), 
1648                         (when() - Time::now()).seconds()); 
1650         Debug::dump(" params=(%u,%u)", mParams
.idleTimeout
, mParams
.lockOnSleep
); 
1653 void KeychainDatabase::dumpNode() 
1655         PerProcess::dumpNode(); 
1656         Debug::dump(" %s vers=%u", 
1657                 mValidData 
? " data" : " nodata", version
); 
1659                 uint32 sig
; memcpy(&sig
, &mBlob
->randomSignature
, sizeof(sig
)); 
1660                 Debug::dump(" blob=%p[%8.8x]", mBlob
, sig
); 
1662                 Debug::dump(" noblob"); 
1670 // DbCommon basic features 
1672 KeychainDbCommon::KeychainDbCommon(Session 
&ssn
, const DbIdentifier 
&id
, uint32 requestedVersion
) 
1673         : LocalDbCommon(ssn
), DatabaseCryptoCore(requestedVersion
), sequence(0), version(1), mIdentifier(id
), 
1674       mIsLocked(true), mValidParams(false), mLoginKeychain(false) 
1676     // match existing DbGlobal or create a new one 
1678         Server 
&server 
= Server::active(); 
1679         StLock
<Mutex
> _(server
); 
1680         if (KeychainDbGlobal 
*dbglobal 
= 
1681                 server
.findFirst
<KeychainDbGlobal
, const DbIdentifier 
&>(&KeychainDbGlobal::identifier
, identifier())) { 
1683             secinfo("KCdb", "%p linking to existing DbGlobal %p", this, dbglobal
); 
1685             // DbGlobal not present; make a new one 
1686             parent(*new KeychainDbGlobal(identifier())); 
1687             secinfo("KCdb", "%p linking to new DbGlobal %p", this, &global()); 
1690         // link lifetime to the Session 
1691         session().addReference(*this); 
1693         if (strcasestr(id
.dbName(), "login.keychain") != NULL
) { 
1694             mLoginKeychain 
= true; 
1699 void KeychainDbCommon::initializeKeybag() { 
1700     if (mLoginKeychain 
&& !session().keybagGetState(session_keybag_loaded
)) { 
1701         service_context_t context 
= session().get_current_service_context(); 
1702         if (service_client_kb_load(&context
) == 0) { 
1703             session().keybagSetState(session_keybag_loaded
); 
1708 KeychainDbCommon::KeychainDbCommon(Session 
&ssn
, const DbIdentifier 
&id
, KeychainDbCommon
& toClone
) 
1709     : LocalDbCommon(ssn
), DatabaseCryptoCore(toClone
.mBlobVersion
), sequence(toClone
.sequence
), mParams(toClone
.mParams
), version(toClone
.version
), 
1710     mIdentifier(id
), mIsLocked(toClone
.mIsLocked
), mValidParams(toClone
.mValidParams
), mLoginKeychain(toClone
.mLoginKeychain
) 
1715         Server 
&server 
= Server::active(); 
1716         StLock
<Mutex
> _(server
); 
1717         if (KeychainDbGlobal 
*dbglobal 
= 
1718             server
.findFirst
<KeychainDbGlobal
, const DbIdentifier 
&>(&KeychainDbGlobal::identifier
, identifier())) { 
1720             secinfo("KCdb", "%p linking to existing DbGlobal %p", this, dbglobal
); 
1722             // DbGlobal not present; make a new one 
1723             parent(*new KeychainDbGlobal(identifier())); 
1724             secinfo("KCdb", "%p linking to new DbGlobal %p", this, &global()); 
1726         session().addReference(*this); 
1730 KeychainDbCommon::~KeychainDbCommon() 
1732     secinfo("KCdb", "releasing keychain %p %s", this, (char*)this->dbName()); 
1734         // explicitly unschedule ourselves 
1735         Server::active().clearTimer(this); 
1736     if (mLoginKeychain
) { 
1737         session().keybagClearState(session_keybag_unlocked
); 
1739     // remove ourselves from mCommonSet 
1743 void KeychainDbCommon::cloneFrom(KeychainDbCommon
& toClone
, uint32 requestedVersion
) { 
1744     // don't clone the mIdentifier 
1745     sequence 
= toClone
.sequence
; 
1746     mParams 
= toClone
.mParams
; 
1747     version 
= toClone
.version
; 
1748     mIsLocked 
= toClone
.mIsLocked
; 
1749     mValidParams 
= toClone
.mValidParams
; 
1750     mLoginKeychain 
= toClone
.mLoginKeychain
; 
1752     DatabaseCryptoCore::initializeFrom(toClone
, requestedVersion
); 
1755 void KeychainDbCommon::kill() 
1757     StReadWriteLock 
_(mRWCommonLock
, StReadWriteLock::Write
); 
1758     mCommonSet
.erase(this); 
1761 KeychainDbGlobal 
&KeychainDbCommon::global() const 
1763         return parent
<KeychainDbGlobal
>(); 
1767 void KeychainDbCommon::select() 
1770 void KeychainDbCommon::unselect() 
1775 void KeychainDbCommon::makeNewSecrets() 
1777         // we already have a master key (right?) 
1778         assert(hasMaster()); 
1780         // tell crypto core to generate the use keys 
1781         DatabaseCryptoCore::generateNewSecrets(); 
1783         // we're now officially "unlocked"; set the timer 
1789 // All unlocking activity ultimately funnels through this method. 
1790 // This unlocks a DbCommon using the secrets setup in its crypto core 
1791 // component, and performs all the housekeeping needed to represent 
1792 // the state change. 
1793 // Returns true if unlock was successful, false if it failed due to 
1794 // invalid/insufficient secrets. Throws on other errors. 
1796 bool KeychainDbCommon::unlockDb(DbBlob 
*blob
, void **privateAclBlob
) 
1799                 // Tell the cryptocore to (try to) decode itself. This will fail 
1800                 // in an astonishing variety of ways if the passphrase is wrong. 
1801                 assert(hasMaster()); 
1802                 decodeCore(blob
, privateAclBlob
); 
1803                 secinfo("KCdb", "%p unlock successful", this); 
1805                 secinfo("KCdb", "%p unlock failed", this); 
1809         // get the database parameters only if we haven't got them yet 
1810         if (!mValidParams
) { 
1811                 mParams 
= blob
->params
; 
1812                 n2hi(mParams
.idleTimeout
); 
1813                 mValidParams 
= true;    // sticky 
1816         bool isLocked 
= mIsLocked
; 
1818         setUnlocked();          // mark unlocked 
1821                 // broadcast unlock notification, but only if we were previously locked 
1822                 notify(kNotificationEventUnlocked
); 
1823         secinfo("KCdb", "unlocking keychain %p %s", this, (char*)this->dbName()); 
1828 void KeychainDbCommon::setUnlocked() 
1830         session().addReference(*this);  // active/held 
1831         mIsLocked 
= false;                              // mark unlocked 
1832         activity();                                             // set timeout timer 
1836 void KeychainDbCommon::lockDb() 
1840         StLock
<Mutex
> _(*this); 
1842             DatabaseCryptoCore::invalidate(); 
1843             notify(kNotificationEventLocked
); 
1844             secinfo("KCdb", "locking keychain %p %s", this, (char*)this->dbName()); 
1845             Server::active().clearTimer(this); 
1847             mIsLocked 
= true;           // mark locked 
1850             // this call may destroy us if we have no databases anymore 
1851             session().removeReference(*this); 
1857 DbBlob 
*KeychainDbCommon::encode(KeychainDatabase 
&db
) 
1859     assert(!isLocked());        // must have been unlocked by caller 
1861     // export database ACL to blob form 
1862     CssmData pubAcl
, privAcl
; 
1863     db
.acl().exportBlob(pubAcl
, privAcl
); 
1865     // tell the cryptocore to form the blob 
1867     form
.randomSignature 
= identifier(); 
1868     form
.sequence 
= sequence
; 
1869     form
.params 
= mParams
; 
1870         h2ni(form
.params
.idleTimeout
); 
1872         assert(hasMaster()); 
1873     DbBlob 
*blob 
= encodeCore(form
, pubAcl
, privAcl
); 
1876     db
.acl().allocator
.free(pubAcl
); 
1877     db
.acl().allocator
.free(privAcl
); 
1883 // Perform deferred lock processing for a database. 
1885 void KeychainDbCommon::action() 
1887         secinfo("KCdb", "common %s(%p) locked by timer", dbName(), this); 
1891 void KeychainDbCommon::activity() 
1894                 secinfo("KCdb", "setting DbCommon %p timer to %d", 
1895                         this, int(mParams
.idleTimeout
)); 
1896                 Server::active().setTimer(this, Time::Interval(int(mParams
.idleTimeout
))); 
1900 void KeychainDbCommon::sleepProcessing() 
1902         secinfo("KCdb", "common %s(%p) sleep-lock processing", dbName(), this); 
1903     if (mParams
.lockOnSleep 
&& !isDefaultSystemKeychain()) { 
1904         StLock
<Mutex
> _(*this); 
1909 void KeychainDbCommon::lockProcessing() 
1916 // We consider a keychain to belong to the system domain if it resides 
1917 // in /Library/Keychains. That's not exactly fool-proof, but we don't 
1918 // currently have any internal markers to interrogate. 
1920 bool KeychainDbCommon::belongsToSystem() const 
1922     if (const char *name 
= this->dbName()) 
1923         return !strncmp(name
, "/Library/Keychains/", 19); 
1927 bool KeychainDbCommon::isDefaultSystemKeychain() const 
1929     // /Library/Keychains/System.keychain (34) 
1930     if (const char *name 
= this->dbName()) 
1931         return !strncmp(name
, "/Library/Keychains/System.keychain", 34); 
1936 // Keychain global objects 
1938 KeychainDbGlobal::KeychainDbGlobal(const DbIdentifier 
&id
) 
1943 KeychainDbGlobal::~KeychainDbGlobal() 
1945         secinfo("KCdb", "DbGlobal %p destroyed", this);