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 "SecRandom.h" 
  47 #include <vector>           // @@@  4003540 workaround 
  48 #include <security_cdsa_utilities/acl_any.h>    // for default owner ACLs 
  49 #include <security_cdsa_utilities/cssmendian.h> 
  50 #include <security_cdsa_client/wrapkey.h> 
  51 #include <security_cdsa_client/genkey.h> 
  52 #include <security_cdsa_client/signclient.h> 
  53 #include <security_cdsa_client/cryptoclient.h> 
  54 #include <security_cdsa_client/macclient.h> 
  55 #include <securityd_client/dictionary.h> 
  56 #include <security_utilities/endian.h> 
  57 #include <security_utilities/errors.h> 
  58 #include "securityd_service/securityd_service/securityd_service_client.h" 
  59 #include <AssertMacros.h> 
  61 #include <sys/sysctl.h> 
  62 #include <sys/kauth.h> 
  65 #include <corecrypto/ccmode_siv.h> 
  68 void unflattenKey(const CssmData 
&flatKey
, CssmKey 
&rawKey
);    //>> make static method on KeychainDatabase 
  73 KeychainDbCommon::CommonSet 
KeychainDbCommon::mCommonSet
; 
  74 ReadWriteLock 
KeychainDbCommon::mRWCommonLock
; 
  76 // Process is using a cached effective uid, login window switches uid after the intial connection 
  77 static void get_process_euid(pid_t pid
, uid_t 
* out_euid
) 
  79     if (!out_euid
) return; 
  81     struct kinfo_proc proc_info 
= {}; 
  82     int mib
[] = {CTL_KERN
, KERN_PROC
, KERN_PROC_PID
, pid
}; 
  83     size_t len 
= sizeof(struct kinfo_proc
); 
  85     ret 
= sysctl(mib
, (sizeof(mib
)/sizeof(int)), &proc_info
, &len
, NULL
, 0); 
  88     if ((ret 
== 0) && (proc_info
.kp_eproc
.e_ucred
.cr_uid 
!= 0)) { 
  89         *out_euid 
= proc_info
.kp_eproc
.e_ucred
.cr_uid
; 
  94 unlock_keybag(KeychainDatabase 
& db
, const void * secret
, int secret_len
) 
  98     if (!db
.common().isLoginKeychain()) return 0; 
 100     service_context_t context 
= db
.common().session().get_current_service_context(); 
 102     // login window attempts to change the password before a session has a uid 
 103     if (context
.s_uid 
== AU_DEFAUDITID
) { 
 104         get_process_euid(db
.process().pid(), &context
.s_uid
); 
 107     // try to unlock first if not found then load/create or unlock 
 108     // loading should happen when the kb common object is created 
 109     // if it doesn't exist yet then the unlock will fail and we'll create everything 
 110     rc 
= service_client_kb_unlock(&context
, secret
, secret_len
); 
 111     if (rc 
== KB_BagNotLoaded
) { 
 112         if (service_client_kb_load(&context
) == KB_BagNotFound
) { 
 113             rc 
= service_client_kb_create(&context
, secret
, secret_len
); 
 115             rc 
= service_client_kb_unlock(&context
, secret
, secret_len
); 
 119     if (rc 
!= 0) { // if we just upgraded make sure we swap the encryption key to the password 
 120         if (!db
.common().session().keybagGetState(session_keybag_check_master_key
)) { 
 121             CssmAutoData 
encKey(Allocator::standard(Allocator::sensitive
)); 
 122             db
.common().get_encryption_key(encKey
); 
 123             if ((rc 
= service_client_kb_unlock(&context
, encKey
.data(), (int)encKey
.length())) == 0) { 
 124                 rc 
= service_client_kb_change_secret(&context
, encKey
.data(), (int)encKey
.length(), secret
, secret_len
); 
 127             if (rc 
!= 0) { // if a login.keychain password exists but doesnt on the keybag update it 
 129                 if ((secret_len 
> 0) && service_client_kb_is_locked(&context
, NULL
, &no_pin
) == 0) { 
 131                         syslog(LOG_ERR
, "Updating iCloud keychain passphrase for uid %d", context
.s_uid
); 
 132                         service_client_kb_change_secret(&context
, NULL
, 0, secret
, secret_len
); 
 136         } // session_keybag_check_master_key 
 140         db
.common().session().keybagSetState(session_keybag_unlocked
|session_keybag_loaded
|session_keybag_check_master_key
); 
 142         syslog(LOG_ERR
, "Failed to unlock iCloud keychain for uid %d", context
.s_uid
); 
 149 change_secret_on_keybag(KeychainDatabase 
& db
, const void * secret
, int secret_len
, const void * new_secret
, int new_secret_len
) 
 151     if (!db
.common().isLoginKeychain()) return; 
 153     service_context_t context 
= db
.common().session().get_current_service_context(); 
 155     // login window attempts to change the password before a session has a uid 
 156     if (context
.s_uid 
== AU_DEFAUDITID
) { 
 157         get_process_euid(db
.process().pid(), &context
.s_uid
); 
 160     // if a login.keychain doesn't exist yet it comes into securityd as a create then change_secret 
 161     // we need to create the keybag in this case if it doesn't exist 
 162     int rc 
= service_client_kb_change_secret(&context
, secret
, secret_len
, new_secret
, new_secret_len
); 
 163     if (rc 
== KB_BagNotLoaded
) { 
 164         if (service_client_kb_load(&context
) == KB_BagNotFound
) { 
 165             rc 
= service_client_kb_create(&context
, new_secret
, new_secret_len
); 
 167             rc 
= service_client_kb_change_secret(&context
, secret
, secret_len
, new_secret
, new_secret_len
); 
 171     // this makes it possible to restore a deleted keybag on condition it still exists in kernel 
 172     if (rc 
!= KB_Success
) { 
 173         service_client_kb_save(&context
); 
 176     // if for some reason we are locked lets unlock so later we don't try and throw up SecurityAgent dialog 
 178     if ((service_client_kb_is_locked(&context
, &locked
, NULL
) == KB_Success
) && locked
) { 
 179         rc 
= service_client_kb_unlock(&context
, new_secret
, new_secret_len
); 
 180         if (rc 
!= KB_Success
) { 
 181             syslog(LOG_ERR
, "Failed to unlock iCloud keychain for uid %d (%d)", context
.s_uid
, (int)rc
); 
 186 // Attempt to unlock the keybag with a AccessCredentials password. 
 187 // Honors UI disabled flags from clients set in the cred before prompt. 
 189 unlock_keybag_with_cred(KeychainDatabase 
&db
, const AccessCredentials 
*cred
){ 
 190     list
<CssmSample
> samples
; 
 191     if (cred 
&& cred
->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK
, samples
)) { 
 192         for (list
<CssmSample
>::iterator it 
= samples
.begin(); it 
!= samples
.end(); it
++) { 
 193             TypedList 
&sample 
= *it
; 
 194             sample
.checkProper(); 
 195             switch (sample
.type()) { 
 196                 // interactively prompt the user - no additional data 
 197                 case CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT
: 
 200                      Okay, this is messy. We need to hold the common lock to be certain we're modifying the world 
 201                      as we intend. But UI ^ common, and QueryKeybagPassphrase::query() has tons of side effects by necessity, 
 202                      so just confirm that the operation did what we wanted after the fact. 
 204                     bool query_success 
= false; 
 205                     bool unlock_success 
= false; 
 209                             StSyncLock
<Mutex
, Mutex
> uisync(db
.common().uiLock(), db
.common()); 
 210                             // Once we get the ui lock, check whether another thread has already unlocked keybag 
 212                             query_success 
= false; 
 213                             service_context_t context 
= db
.common().session().get_current_service_context(); 
 214                             if ((service_client_kb_is_locked(&context
, &locked
, NULL
) == 0) && locked
) { 
 215                                 QueryKeybagPassphrase 
keybagQuery(db
.common().session(), 3); 
 216                                 keybagQuery
.inferHints(Server::process()); 
 217                                 if (keybagQuery
.query() == SecurityAgent::noReason
) { 
 218                                     query_success 
= true; 
 221                                 // another thread already unlocked the keybag 
 222                                 query_success 
= true;   // NOT unlock_success because we have the wrong lock 
 224                         }   // StSyncLock goes out of scope, we have common lock again 
 226                         service_context_t context 
= db
.common().session().get_current_service_context(); 
 227                         if ((service_client_kb_is_locked(&context
, &locked
, NULL
) == 0) && !locked
) { 
 228                             unlock_success 
= true; 
 231                             secnotice("KCdb", "Unlocking the keybag again (threading?)"); 
 234                     } while (query_success 
&& !unlock_success
); 
 237                 // try to use an explicitly given passphrase - Data:passphrase 
 238                 case CSSM_SAMPLE_TYPE_PASSWORD
: { 
 239                     if (sample
.length() != 2) 
 240                         CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
); 
 241                     secinfo("KCdb", "attempting passphrase unlock of keybag"); 
 242                     if (unlock_keybag(db
, sample
[1].data().data(), (int)sample
[1].data().length())) { 
 248                     // Unknown sub-sample for unlocking. 
 249                     secinfo("KCdb", "keybag: unknown sub-sample unlock (%d) ignored", sample
.type()); 
 259 // Create a Database object from initial parameters (create operation) 
 261 KeychainDatabase::KeychainDatabase(const DLDbIdentifier 
&id
, const DBParameters 
¶ms
, Process 
&proc
, 
 262             const AccessCredentials 
*cred
, const AclEntryPrototype 
*owner
) 
 263     : LocalDatabase(proc
), mValidData(false), mSecret(Allocator::standard(Allocator::sensitive
)), mSaveSecret(false), version(0), mBlob(NULL
), mRecoded(false) 
 265     // save a copy of the credentials for later access control 
 266     mCred 
= DataWalkers::copy(cred
, Allocator::standard()); 
 268     // create a new random signature to complete the DLDbIdentifier 
 269     DbBlob::Signature newSig
; 
 271     (MacOSError::check
)(SecRandomCopyBytes(kSecRandomDefault
, sizeof(newSig
.bytes
), newSig
.bytes
)); 
 272     DbIdentifier 
ident(id
, newSig
); 
 274     // create common block and initialize 
 275     // Since this is a creation step, figure out the correct blob version for this database 
 276     RefPointer
<KeychainDbCommon
> newCommon 
= new KeychainDbCommon(proc
.session(), ident
, CommonBlob::getCurrentVersionForDb(ident
.dbName())); 
 277     newCommon
->initializeKeybag(); 
 279         StLock
<Mutex
> _(*newCommon
); 
 282         // new common is now visible (in ident-map) but we hold its lock 
 284         // establish the new master secret 
 285         establishNewSecrets(cred
, SecurityAgent::newDatabase
, false); 
 287         // set initial database parameters 
 288         common().mParams 
= params
; 
 290         // the common is "unlocked" now 
 291         common().makeNewSecrets(); 
 293         // establish initial ACL 
 295                 acl().cssmSetInitial(*owner
); 
 297                 acl().cssmSetInitial(new AnyAclSubject()); 
 300     // for now, create the blob immediately 
 303         proc
.addReference(*this); 
 305         // this new keychain is unlocked; make it so 
 308     secinfo("KCdb", "creating keychain %p %s with common %p", this, (char*)this->dbName(), &common()); 
 313 // Create a Database object from a database blob (decoding) 
 315 KeychainDatabase::KeychainDatabase(const DLDbIdentifier 
&id
, const DbBlob 
*blob
, Process 
&proc
, 
 316     const AccessCredentials 
*cred
) 
 317         : LocalDatabase(proc
), mValidData(false), mSecret(Allocator::standard(Allocator::sensitive
)), mSaveSecret(false), version(0), mBlob(NULL
), mRecoded(false) 
 321     // save a copy of the credentials for later access control 
 322     mCred 
= DataWalkers::copy(cred
, Allocator::standard()); 
 323     mBlob 
= blob
->copy(); 
 325     // check to see if we already know about this database 
 326     DbIdentifier 
ident(id
, blob
->randomSignature
); 
 327         Session 
&session 
= process().session(); 
 328         RefPointer
<KeychainDbCommon
> com
; 
 329     secinfo("kccommon", "looking for a common at %s", ident
.dbName()); 
 330         if (KeychainDbCommon::find(ident
, session
, com
)) { 
 332         secinfo("KCdb", "joining keychain %p %s with common %p", this, (char*)this->dbName(), &common()); 
 334                 // DbCommon not present; make a new one 
 335         secinfo("kccommon", "no common found"); 
 337                 common().mParams 
= blob
->params
; 
 338         secinfo("KCdb", "making keychain %p %s with common %p", this, (char*)this->dbName(), &common()); 
 339                 // this DbCommon is locked; no timer or reference setting 
 341         proc
.addReference(*this); 
 344 void KeychainDbCommon::insert() 
 346     StReadWriteLock 
_(mRWCommonLock
, StReadWriteLock::Write
); 
 350 void KeychainDbCommon::insertHoldingLock() 
 352     mCommonSet
.insert(this); 
 357 // find or make a DbCommon. Returns true if an existing one was found and used. 
 358 bool KeychainDbCommon::find(const DbIdentifier 
&ident
, Session 
&session
, RefPointer
<KeychainDbCommon
> &common
, uint32 requestedVersion
, KeychainDbCommon
* cloneFrom
) 
 360     // Prepare to drop the mRWCommonLock. 
 362         StReadWriteLock 
_(mRWCommonLock
, StReadWriteLock::Read
); 
 363         for (CommonSet::const_iterator it 
= mCommonSet
.begin(); it 
!= mCommonSet
.end(); ++it
) { 
 364             if (&session 
== &(*it
)->session() && ident 
== (*it
)->identifier()) { 
 366                 secinfo("kccommon", "found a common for %s at %p", ident
.dbName(), common
.get()); 
 372     // not found. Grab the write lock, ensure that nobody has beaten us to adding, 
 373     // and then create a DbCommon and add it to the map. 
 375         StReadWriteLock 
_(mRWCommonLock
, StReadWriteLock::Write
); 
 376         for (CommonSet::const_iterator it 
= mCommonSet
.begin(); it 
!= mCommonSet
.end(); ++it
) { 
 377             if (&session 
== &(*it
)->session() && ident 
== (*it
)->identifier()) { 
 379                 secinfo("kccommon", "found a common for %s at %p", ident
.dbName(), common
.get()); 
 386             common 
= new KeychainDbCommon(session
, ident
, *cloneFrom
); 
 387         } else if(requestedVersion 
!= CommonBlob::version_none
) { 
 388             common 
= new KeychainDbCommon(session
, ident
, requestedVersion
); 
 390             common 
= new KeychainDbCommon(session
, ident
); 
 393         secinfo("kccommon", "made a new common for %s at %p", ident
.dbName(), common
.get()); 
 395         // Can't call insert() here, because it grabs the write lock (which we have). 
 396         common
->insertHoldingLock(); 
 398     common
->initializeKeybag(); 
 404 // Special-purpose constructor for keychain synchronization.  Copies an 
 405 // existing keychain but uses the operational keys from secretsBlob.  The  
 406 // new KeychainDatabase will silently replace the existing KeychainDatabase 
 407 // as soon as the client declares that re-encoding of all keychain items is 
 408 // finished.  This is a little perilous since it allows a client to dictate 
 409 // securityd state, but we try to ensure that only the client that started  
 410 // the re-encoding can declare it done.   
 412 KeychainDatabase::KeychainDatabase(KeychainDatabase 
&src
, Process 
&proc
, DbHandle dbToClone
) 
 413         : LocalDatabase(proc
), mValidData(false), mSecret(Allocator::standard(Allocator::sensitive
)), mSaveSecret(false), version(0), mBlob(NULL
), mRecoded(false) 
 415         mCred 
= DataWalkers::copy(src
.mCred
, Allocator::standard()); 
 417         // Give this KeychainDatabase a temporary name 
 418         std::string newDbName 
= std::string("////") + std::string(src
.identifier().dbName()); 
 419         DLDbIdentifier 
newDLDbIdent(src
.identifier().dlDbIdentifier().ssuid(), newDbName
.c_str(), src
.identifier().dlDbIdentifier().dbLocation()); 
 420         DbIdentifier 
ident(newDLDbIdent
, src
.identifier()); 
 422     // create common block and initialize 
 423         RefPointer
<KeychainDbCommon
> newCommon 
= new KeychainDbCommon(proc
.session(), ident
); 
 424     newCommon
->initializeKeybag(); 
 425         StLock
<Mutex
> _(*newCommon
); 
 429         // set initial database parameters from the source keychain 
 430         common().mParams 
= src
.common().mParams
; 
 432         // establish the source keychain's master secret as ours 
 433         // @@@  NB: this is a v. 0.1 assumption.  We *should* trigger new UI  
 434         //      that offers the user the option of using the existing password  
 435         //      or choosing a new one.  That would require a new  
 436         //      SecurityAgentQuery type, new UI, and--possibly--modifications to 
 437         //      ensure that the new password is available here to generate the  
 438         //      new master secret.   
 439         src
.unlockDb(false);            // precaution for masterKey() 
 440         common().setup(src
.blob(), src
.common().masterKey()); 
 442     // import the operational secrets 
 443         RefPointer
<KeychainDatabase
> srcKC 
= Server::keychain(dbToClone
); 
 444         common().importSecrets(srcKC
->common()); 
 446         // import source keychain's ACL   
 447         CssmData pubAcl
, privAcl
; 
 448         src
.acl().exportBlob(pubAcl
, privAcl
); 
 449         importBlob(pubAcl
.data(), privAcl
.data()); 
 450         src
.acl().allocator
.free(pubAcl
); 
 451         src
.acl().allocator
.free(privAcl
); 
 453         // indicate that this keychain should be allowed to do some otherwise 
 454         // risky things required for copying, like re-encoding keys 
 455         mRecodingSource 
= &src
; 
 457         common().setUnlocked(); 
 462         proc
.addReference(*this); 
 463         secinfo("SSdb", "database %s(%p) created as copy, common at %p", 
 464                          common().dbName(), this, &common()); 
 467 // Make a new KeychainDatabase from an old one, but have a completely different location 
 468 KeychainDatabase::KeychainDatabase(const DLDbIdentifier
& id
, KeychainDatabase 
&src
, Process 
&proc
) 
 469 : LocalDatabase(proc
), mValidData(false), mSecret(Allocator::standard(Allocator::sensitive
)), mSaveSecret(false), version(0), mBlob(NULL
), mRecoded(false) 
 471     mCred 
= DataWalkers::copy(src
.mCred
, Allocator::standard()); 
 473     DbIdentifier 
ident(id
, src
.identifier()); 
 475     // create common block and initialize 
 476     RefPointer
<KeychainDbCommon
> newCommon
; 
 477     if(KeychainDbCommon::find(ident
, process().session(), newCommon
, CommonBlob::version_none
, &src
.common())) { 
 478         // A common already existed. Write over it, but note that everything may go horribly from here on out. 
 479         secinfo("kccommon", "Found common where we didn't expect. Possible strange behavior ahead."); 
 480         newCommon
->cloneFrom(src
.common()); 
 483     StLock
<Mutex
> _(*newCommon
); 
 486     // set initial database parameters from the source keychain 
 487     common().mParams 
= src
.common().mParams
; 
 489     // import source keychain's ACL 
 490     CssmData pubAcl
, privAcl
; 
 491     src
.acl().exportBlob(pubAcl
, privAcl
); 
 492     importBlob(pubAcl
.data(), privAcl
.data()); 
 493     src
.acl().allocator
.free(pubAcl
); 
 494     src
.acl().allocator
.free(privAcl
); 
 496     // Copy the source database's blob, if possible 
 498         mBlob 
= src
.mBlob
->copy(); 
 499         version 
= src
.version
; 
 502     // We've copied everything we can from our source. If they were valid, so are we. 
 503     mValidData 
= src
.mValidData
; 
 505     proc
.addReference(*this); 
 506     secinfo("SSdb", "database %s(%p) created as expected clone, common at %p", common().dbName(), this, &common()); 
 510 // Make a new KeychainDatabase from an old one, but have entirely new operational secrets 
 511 KeychainDatabase::KeychainDatabase(uint32 requestedVersion
, KeychainDatabase 
&src
, Process 
&proc
) 
 512 : LocalDatabase(proc
), mValidData(false), mSecret(Allocator::standard(Allocator::sensitive
)), mSaveSecret(false), version(0), mBlob(NULL
), mRecoded(false) 
 514     mCred 
= DataWalkers::copy(src
.mCred
, Allocator::standard()); 
 516     // Give this KeychainDatabase a temporary name 
 517     // this must canonicalize to a different path than the original DB, otherwise another process opening the existing DB wil find this new KeychainDbCommon 
 518     // and call decodeCore with the old blob, overwriting the new secrets and wreaking havoc 
 519     std::string newDbName 
= std::string("////") + std::string(src
.identifier().dbName()) + std::string("_com.apple.security.keychain.migrating"); 
 520     DLDbIdentifier 
newDLDbIdent(src
.identifier().dlDbIdentifier().ssuid(), newDbName
.c_str(), src
.identifier().dlDbIdentifier().dbLocation()); 
 521     DbIdentifier 
ident(newDLDbIdent
, src
.identifier()); 
 523     // hold the lock for src's common during this operation (to match locking common locking order with KeychainDatabase::recodeKey) 
 524     StLock
<Mutex
> __(src
.common()); 
 526     // create common block and initialize 
 527     RefPointer
<KeychainDbCommon
> newCommon
; 
 528     if(KeychainDbCommon::find(ident
, process().session(), newCommon
, requestedVersion
)) { 
 529         // A common already existed here. Write over it, but note that everything may go horribly from here on out. 
 530         secinfo("kccommon", "Found common where we didn't expect. Possible strange behavior ahead."); 
 531         newCommon
->cloneFrom(src
.common(), requestedVersion
); 
 533     newCommon
->initializeKeybag(); 
 534     StLock
<Mutex
> _(*newCommon
); 
 537     // We want to re-use the master secrets from the source database (and so the 
 538     // same password), but reroll new operational secrets. 
 540     // Copy the master secret over... 
 541     src
.unlockDb(false); // precaution 
 543     common().setup(src
.blob(), src
.common().masterKey(), false); // keep the new common's version intact 
 545     // set initial database parameters from the source keychain 
 546     common().mParams 
= src
.common().mParams
; 
 548     // and make new operational secrets 
 549     common().makeNewSecrets(); 
 551     // import source keychain's ACL 
 552     CssmData pubAcl
, privAcl
; 
 553     src
.acl().exportBlob(pubAcl
, privAcl
); 
 554     importBlob(pubAcl
.data(), privAcl
.data()); 
 555     src
.acl().allocator
.free(pubAcl
); 
 556     src
.acl().allocator
.free(privAcl
); 
 558     // indicate that this keychain should be allowed to do some otherwise 
 559     // risky things required for copying, like re-encoding keys 
 560     mRecodingSource 
= &src
; 
 562     common().setUnlocked(); 
 567     proc
.addReference(*this); 
 568     secinfo("SSdb", "database %s(%p) created as expected copy, common at %p", 
 569              common().dbName(), this, &common()); 
 573 // Destroy a Database 
 575 KeychainDatabase::~KeychainDatabase() 
 577     secinfo("KCdb", "deleting database %s(%p) common %p", 
 578         common().dbName(), this, &common()); 
 579     Allocator::standard().free(mCred
); 
 580         Allocator::standard().free(mBlob
); 
 585 // Basic Database virtual implementations 
 587 KeychainDbCommon 
&KeychainDatabase::common() const 
 589         return parent
<KeychainDbCommon
>(); 
 592 const char *KeychainDatabase::dbName() const 
 594         return common().dbName(); 
 597 bool KeychainDatabase::transient() const 
 599         return false;   // has permanent store 
 602 AclKind 
KeychainDatabase::aclKind() const 
 607 Database 
*KeychainDatabase::relatedDatabase() 
 613 // (Re-)Authenticate the database. This changes the stored credentials. 
 615 void KeychainDatabase::authenticate(CSSM_DB_ACCESS_TYPE mode
, 
 616         const AccessCredentials 
*cred
) 
 618         StLock
<Mutex
> _(common()); 
 620         // the (Apple specific) RESET bit means "lock the database now" 
 622         case CSSM_DB_ACCESS_RESET
: 
 623                 secinfo("KCdb", "%p ACCESS_RESET triggers keychain lock", this); 
 627                 //  store the new credentials for future use 
 628                 secinfo("KCdb", "%p authenticate stores new database credentials", this); 
 629                 AccessCredentials 
*newCred 
= DataWalkers::copy(cred
, Allocator::standard()); 
 630                 Allocator::standard().free(mCred
); 
 637 // Make a new KeychainKey. 
 638 // If PERMANENT is off, make a temporary key instead. 
 639 // The db argument allows you to create for another KeychainDatabase (only); 
 640 // it defaults to ourselves. 
 642 RefPointer
<Key
> KeychainDatabase::makeKey(Database 
&db
, const CssmKey 
&newKey
, 
 643         uint32 moreAttributes
, const AclEntryPrototype 
*owner
) 
 645     StLock
<Mutex
> lock(common()); 
 646         if (moreAttributes 
& CSSM_KEYATTR_PERMANENT
) 
 647                 return new KeychainKey(db
, newKey
, moreAttributes
, owner
); 
 649                 return process().makeTemporaryKey(newKey
, moreAttributes
, owner
); 
 652 RefPointer
<Key
> KeychainDatabase::makeKey(const CssmKey 
&newKey
, 
 653         uint32 moreAttributes
, const AclEntryPrototype 
*owner
) 
 655         return makeKey(*this, newKey
, moreAttributes
, owner
); 
 660 // Return the database blob, recalculating it as needed. 
 662 DbBlob 
*KeychainDatabase::blob() 
 664         StLock
<Mutex
> _(common()); 
 666         makeUnlocked(false);    // unlock to get master secret 
 667                 encode();                               // (re)encode blob if needed 
 669     activity();                                 // reset timeout 
 670         assert(validBlob());            // better have a valid blob now... 
 676 // Encode the current database as a blob. 
 677 // Note that this returns memory we own and keep. 
 678 // Caller must hold common lock. 
 680 void KeychainDatabase::encode() 
 682         DbBlob 
*blob 
= common().encode(*this); 
 683         Allocator::standard().free(mBlob
); 
 685         version 
= common().version
; 
 686         secinfo("KCdb", "encoded database %p common %p(%s) version %u params=(%u,%u)", 
 687                 this, &common(), dbName(), version
, 
 688                 common().mParams
.idleTimeout
, common().mParams
.lockOnSleep
); 
 692 // Change the passphrase on a database 
 694 void KeychainDatabase::changePassphrase(const AccessCredentials 
*cred
) 
 696         // get and hold the common lock (don't let other threads break in here) 
 697         StLock
<Mutex
> _(common()); 
 699     list
<CssmSample
> samples
; 
 700     bool hasOldSecret 
= cred 
&& cred
->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK
, samples
); 
 701     samples
.clear();    // Can't count the samples at the end because I could specify CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK twice 
 702     bool hasNewSecret 
= cred 
&& cred
->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK
, samples
); 
 704     // If no creds we do interactive, if both we do silently. If unequal, think harder. 
 705     if (hasOldSecret 
!= hasNewSecret
) { 
 706         if (!hasOldSecret 
&& !isLocked()) { 
 707             // Alternative: do a confirm_access SA dialog and run validatePassphrase on it (what client name?) 
 708             // That's risky for now, but it would cover the remaining use case. 
 709             secerror("KCdb: changePassphrase credential set has no old secret and KC not locked"); 
 710             MacOSError::throwMe(errSecAuthFailed
); 
 714     secnotice("KCdb", "changePassphrase proceeding with old %i, new %i, locked %i", hasOldSecret
, hasNewSecret
, isLocked()); 
 716     if (hasOldSecret 
&& !checkCredentials(cred
)) { 
 717         secinfo("KCdb", "Cannot change passphrase for (%s): existing passphrase does not match", common().dbName()); 
 718         MacOSError::throwMe(errSecAuthFailed
); 
 721         // establish OLD secret - i.e. unlock the database. You'll be prompted if !hasOldSecrets and DB is locked. 
 722     if (common().isLoginKeychain()) mSaveSecret 
= true; 
 723         makeUnlocked(cred
, false); 
 725     // establish NEW secret 
 726     if(!establishNewSecrets(cred
, SecurityAgent::changePassphrase
, true)) { 
 727         secinfo("KCdb", "Old and new passphrases are the same. Database %s(%p) master secret did not change.", 
 728                  common().dbName(), this); 
 731     if (mSecret
) { mSecret
.reset(); } 
 733         common().invalidateBlob();      // blob state changed 
 734         secinfo("KCdb", "Database %s(%p) master secret changed", common().dbName(), this); 
 735         encode();                       // force rebuild of local blob 
 737         // send out a notification 
 738         notify(kNotificationEventPassphraseChanged
); 
 740     // I guess this counts as an activity 
 745 // Second stage of keychain synchronization: overwrite the original keychain's 
 746 // (this KeychainDatabase's) operational secrets 
 748 void KeychainDatabase::commitSecretsForSync(KeychainDatabase 
&cloneDb
) 
 750     StLock
<Mutex
> _(common()); 
 752         // try to detect spoofing 
 753         if (cloneDb
.mRecodingSource 
!= this)  
 754         CssmError::throwMe(CSSM_ERRCODE_INVALID_DB_HANDLE
); 
 756     // in case we autolocked since starting the sync 
 757     makeUnlocked(false); // call this because we already own the lock 
 758         cloneDb
.unlockDb(false); // we may not own the lock here, so calling unlockDb will lock the cloneDb's common lock 
 760     // Decode all keys whose handles refer to this on-disk keychain so that 
 761     // if the holding client commits the key back to disk, it's encoded with 
 762     // the new operational secrets.  The recoding client *must* hold a write 
 763     // lock for the on-disk keychain from the moment it starts recoding key 
 764     // items until after this call.   
 766         // @@@  This specific implementation is a workaround for 4003540.   
 767         std::vector
<U32HandleObject::Handle
> handleList
; 
 768         U32HandleObject::findAllRefs
<KeychainKey
>(handleList
); 
 769     size_t count 
= handleList
.size(); 
 771         for (unsigned int n 
= 0; n 
< count
; ++n
) { 
 772             RefPointer
<KeychainKey
> kckey 
=  
 773                 U32HandleObject::findRefAndLock
<KeychainKey
>(handleList
[n
], CSSMERR_CSP_INVALID_KEY_REFERENCE
); 
 774             StLock
<Mutex
> _(*kckey
/*, true*/); 
 775             if (kckey
->database().global().identifier() == identifier()) { 
 776                 kckey
->key();               // force decode 
 777                 kckey
->invalidateBlob(); 
 778                                 secinfo("kcrecode", "changed extant key %p (proc %d)", 
 779                                                  &*kckey
, kckey
->process().pid()); 
 784     // mark down that we just recoded 
 787     // it is now safe to replace the old op secrets 
 788     common().importSecrets(cloneDb
.common()); 
 789         common().invalidateBlob(); 
 794 // Extract the database master key as a proper Key object. 
 796 RefPointer
<Key
> KeychainDatabase::extractMasterKey(Database 
&db
, 
 797         const AccessCredentials 
*cred
, const AclEntryPrototype 
*owner
, 
 798         uint32 usage
, uint32 attrs
) 
 800         // get and hold common lock 
 801         StLock
<Mutex
> _(common()); 
 803         // force lock to require re-validation of credentials 
 806         // unlock to establish master secret 
 809         // extract the raw cryptographic key 
 810         CssmClient::WrapKey 
wrap(Server::csp(), CSSM_ALGID_NONE
); 
 812         wrap(common().masterKey(), key
); 
 814         // make the key object and return it 
 815         return makeKey(db
, key
, attrs 
& LocalKey::managedAttributes
, owner
); 
 820 // Unlock this database (if needed) by obtaining the master secret in some 
 821 // suitable way and then proceeding to unlock with it. 
 822 // Does absolutely nothing if the database is already unlocked. 
 823 // The makeUnlocked forms are identical except the assume the caller already 
 824 // holds the common lock. 
 826 void KeychainDatabase::unlockDb(bool unlockKeybag
) 
 828         StLock
<Mutex
> _(common()); 
 829         makeUnlocked(unlockKeybag
); 
 832 void KeychainDatabase::makeUnlocked(bool unlockKeybag
) 
 834         return makeUnlocked(mCred
, unlockKeybag
); 
 837 void KeychainDatabase::makeUnlocked(const AccessCredentials 
*cred
, bool unlockKeybag
) 
 840                 secnotice("KCdb", "%p(%p) unlocking for makeUnlocked()", this, &common()); 
 841         assert(mBlob 
|| (mValidData 
&& common().hasMaster())); 
 842         bool asking_again 
= false; 
 845                 secnotice("KCdb", "makeUnlocked: establishing old secrets again (threading?)"); 
 847             establishOldSecrets(cred
); 
 849         } while (!common().hasMaster()); 
 850                 common().setUnlocked(); // mark unlocked 
 851         if (common().isLoginKeychain()) { 
 852             CssmKey master 
= common().masterKey(); 
 854             CssmClient::WrapKey 
wrap(Server::csp(), CSSM_ALGID_NONE
); 
 855             wrap(master
, rawMaster
); 
 857             service_context_t context 
= common().session().get_current_service_context(); 
 858             service_client_stash_load_key(&context
, rawMaster
.keyData(), (int)rawMaster
.length()); 
 860         } else if (unlockKeybag 
&& common().isLoginKeychain()) { 
 862         service_context_t context 
= common().session().get_current_service_context(); 
 863         if ((service_client_kb_is_locked(&context
, &locked
, NULL
) == 0) && locked
) { 
 864             if (!unlock_keybag_with_cred(*this, cred
)) { 
 865                 syslog(LOG_NOTICE
, "failed to unlock iCloud keychain"); 
 869         if (!mValidData
) {      // need to decode to get our ACLs, master secret available 
 870                 secnotice("KCdb", "%p(%p) is unlocked; decoding for makeUnlocked()", this, &common()); 
 872                         CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
); 
 879 // Invoke the securityd_service to retrieve the keychain master 
 880 // key from the AppleFDEKeyStore. 
 882 void KeychainDatabase::stashDbCheck() 
 884     CssmAutoData 
masterKey(Allocator::standard(Allocator::sensitive
)); 
 885     CssmAutoData 
encKey(Allocator::standard(Allocator::sensitive
)); 
 889     void * stash_key 
= NULL
; 
 890     int stash_key_len 
= 0; 
 891     service_context_t context 
= common().session().get_current_service_context(); 
 892     rc 
= service_client_stash_get_key(&context
, &stash_key
, &stash_key_len
); 
 895             masterKey
.copy(CssmData((void *)stash_key
,stash_key_len
)); 
 896             memset(stash_key
, 0, stash_key_len
); 
 900         secnotice("KCdb", "failed to get stash from securityd_service: %d", (int)rc
); 
 901         CssmError::throwMe(rc
); 
 905         StLock
<Mutex
> _(common()); 
 907         // Now establish it as the keychain master key 
 908         CssmClient::Key 
key(Server::csp(), masterKey
.get()); 
 909         CssmKey::Header 
&hdr 
= key
.header(); 
 910         hdr
.keyClass(CSSM_KEYCLASS_SESSION_KEY
); 
 911         hdr
.algorithm(CSSM_ALGID_3DES_3KEY_EDE
); 
 912         hdr
.usage(CSSM_KEYUSE_ANY
); 
 913         hdr
.blobType(CSSM_KEYBLOB_RAW
); 
 914         hdr
.blobFormat(CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING
); 
 915         common().setup(mBlob
, key
); 
 918             CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
); 
 920         common().get_encryption_key(encKey
); 
 923     // when upgrading from pre-10.9 create a keybag if it doesn't exist with the encryption key 
 924     // only do this after we have verified the master key unlocks the login.keychain 
 925     if (service_client_kb_load(&context
) == KB_BagNotFound
) { 
 926         service_client_kb_create(&context
, encKey
.data(), (int)encKey
.length()); 
 931 // Get the keychain master key and invoke the securityd_service 
 932 // to stash it in the AppleFDEKeyStore ready for commit to the 
 935 void KeychainDatabase::stashDb() 
 937     CssmAutoData 
data(Allocator::standard(Allocator::sensitive
)); 
 940         StLock
<Mutex
> _(common()); 
 942         if (!common().isValid()) { 
 943             CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
); 
 946         CssmKey key 
= common().masterKey(); 
 947         data
.copy(key
.keyData()); 
 950     service_context_t context 
= common().session().get_current_service_context(); 
 951     int rc 
= service_client_stash_set_key(&context
, data
.data(), (int)data
.length()); 
 952     if (rc 
!= 0) CssmError::throwMe(rc
); 
 956 // The following unlock given an explicit passphrase, rather than using 
 957 // (special cred sample based) default procedures. 
 959 void KeychainDatabase::unlockDb(const CssmData 
&passphrase
, bool unlockKeybag
) 
 961         StLock
<Mutex
> _(common()); 
 962         makeUnlocked(passphrase
, unlockKeybag
); 
 965 void KeychainDatabase::makeUnlocked(const CssmData 
&passphrase
, bool unlockKeybag
) 
 968                 if (decode(passphrase
)) 
 971                         CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
); 
 972         } else if (!mValidData
) {       // need to decode to get our ACLs, passphrase available 
 974                         CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
); 
 977     if (unlockKeybag 
&& common().isLoginKeychain()) { 
 979         service_context_t context 
= common().session().get_current_service_context(); 
 980         if (!common().session().keybagGetState(session_keybag_check_master_key
) || ((service_client_kb_is_locked(&context
, &locked
, NULL
) == 0) && locked
)) { 
 981             unlock_keybag(*this, passphrase
.data(), (int)passphrase
.length()); 
 991 // Nonthrowing passphrase-based unlock. This returns false if unlock failed. 
 992 // Note that this requires an explicitly given passphrase. 
 993 // Caller must hold common lock. 
 995 bool KeychainDatabase::decode(const CssmData 
&passphrase
) 
 998         common().setup(mBlob
, passphrase
); 
 999         bool success 
= decode(); 
1000     if (success 
&& common().isLoginKeychain()) { 
1001         unlock_keybag(*this, passphrase
.data(), (int)passphrase
.length()); 
1008 // Given the established master secret, decode the working keys and other 
1009 // functional secrets for this database. Return false (do NOT throw) if 
1010 // the decode fails. Call this in low(er) level code once you established 
1013 bool KeychainDatabase::decode() 
1016         assert(common().hasMaster()); 
1017         void *privateAclBlob
; 
1018         if (common().unlockDb(mBlob
, &privateAclBlob
)) { 
1020                         acl().importBlob(mBlob
->publicAclBlob(), privateAclBlob
); 
1023                 Allocator::standard().free(privateAclBlob
); 
1026         secinfo("KCdb", "%p decode failed", this); 
1032 // Given an AccessCredentials for this database, wring out the existing primary 
1033 // database secret by whatever means necessary. 
1034 // On entry, caller must hold the database common lock. It will be held 
1035 // throughout except when user interaction is required. User interaction  
1036 // requires relinquishing the database common lock and taking the UI lock. On 
1037 // return from user interaction, the UI lock is relinquished and the database 
1038 // common lock must be reacquired. At no time may the caller hold both locks. 
1039 // On exit, the crypto core has its master secret. If things go wrong, 
1040 // we will throw a suitable exception. Note that encountering any malformed 
1041 // credential sample will throw, but this is not guaranteed -- don't assume 
1042 // that NOT throwing means creds is entirely well-formed (it may just be good 
1043 // enough to work THIS time). 
1046 // Walk through the creds. Fish out those credentials (in order) that 
1047 // are for unlock processing (they have no ACL subject correspondents), 
1048 // and (try to) obey each in turn, until one produces a valid secret 
1049 // or you run out. If no special samples are found at all, interpret that as 
1050 // "use the system global default," which happens to be hard-coded right here. 
1052 void KeychainDatabase::establishOldSecrets(const AccessCredentials 
*creds
) 
1054         bool forSystem 
= this->belongsToSystem();       // this keychain belongs to the system security domain 
1056         // attempt system-keychain unlock 
1058                 SystemKeychainKey 
systemKeychain(kSystemUnlockFile
); 
1059                 if (systemKeychain
.matches(mBlob
->randomSignature
)) { 
1060                         secinfo("KCdb", "%p attempting system unlock", this); 
1061                         common().setup(mBlob
, CssmClient::Key(Server::csp(), systemKeychain
.key(), true)); 
1067         list
<CssmSample
> samples
; 
1068         if (creds 
&& creds
->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK
, samples
)) { 
1069                 for (list
<CssmSample
>::iterator it 
= samples
.begin(); it 
!= samples
.end(); it
++) { 
1070                         TypedList 
&sample 
= *it
; 
1071                         sample
.checkProper(); 
1072                         switch (sample
.type()) { 
1073                         // interactively prompt the user - no additional data 
1074                         case CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT
: 
1076                                         if (interactiveUnlock()) 
1080                         // try to use an explicitly given passphrase - Data:passphrase 
1081                         case CSSM_SAMPLE_TYPE_PASSWORD
: 
1082                                 if (sample
.length() != 2) 
1083                                         CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
); 
1084                                 secinfo("KCdb", "%p attempting passphrase unlock", this); 
1085                                 if (decode(sample
[1])) 
1088                         // try to open with a given master key - Data:CSP or KeyHandle, Data:CssmKey 
1089                         case CSSM_SAMPLE_TYPE_SYMMETRIC_KEY
: 
1090                         case CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY
: 
1092                                 secinfo("KCdb", "%p attempting explicit key unlock", this); 
1093                                 common().setup(mBlob
, keyFromCreds(sample
, 4)); 
1098                         case CSSM_SAMPLE_TYPE_KEYBAG_KEY
: 
1100                                 secinfo("KCdb", "%p attempting keybag key unlock", this); 
1101                                 common().setup(mBlob
, keyFromKeybag(sample
)); 
1106                         // explicitly defeat the default action but don't try anything in particular 
1107                         case CSSM_WORDID_CANCELED
: 
1108                                 secinfo("KCdb", "%p defeat default action", this); 
1111                                 // Unknown sub-sample for unlocking. 
1112                                 // If we wanted to be fascist, we could now do 
1113                                 //  CssmError::throwMe(CSSM_ERRCODE_SAMPLE_VALUE_NOT_SUPPORTED); 
1114                                 // But instead we try to be tolerant and continue on. 
1115                                 // This DOES however count as an explicit attempt at specifying unlock, 
1116                                 // so we will no longer try the default case below... 
1117                                 secinfo("KCdb", "%p unknown sub-sample unlock (%d) ignored", this, sample
.type()); 
1126                         if (interactiveUnlock()) 
1131         // out of options - no secret obtained 
1132         CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
); 
1136 // This function is almost identical to establishOldSecrets, but: 
1137 //   1. It will never prompt the user; these credentials either work or they don't 
1138 //   2. It will not change the secrets of this database 
1140 // TODO: These two functions should probably be refactored to something nicer. 
1141 bool KeychainDatabase::checkCredentials(const AccessCredentials 
*creds
) { 
1143     list
<CssmSample
> samples
; 
1144     if (creds 
&& creds
->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK
, samples
)) { 
1145         for (list
<CssmSample
>::iterator it 
= samples
.begin(); it 
!= samples
.end(); it
++) { 
1146             TypedList 
&sample 
= *it
; 
1147             sample
.checkProper(); 
1148             switch (sample
.type()) { 
1149                 // interactively prompt the user - no additional data 
1150                 case CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT
: 
1151                     // do nothing, because this function will never prompt the user 
1152                     secinfo("integrity", "%p ignoring keychain prompt", this); 
1154                 // try to use an explicitly given passphrase - Data:passphrase 
1155                 case CSSM_SAMPLE_TYPE_PASSWORD
: 
1156                     if (sample
.length() != 2) 
1157                         CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
); 
1158                     secinfo("integrity", "%p checking passphrase", this); 
1159                     if(validatePassphrase(sample
[1])) { 
1163                 // try to open with a given master key - Data:CSP or KeyHandle, Data:CssmKey 
1164                 case CSSM_SAMPLE_TYPE_SYMMETRIC_KEY
: 
1165                 case CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY
: 
1167                     secinfo("integrity", "%p attempting explicit key unlock", this); 
1169                         CssmClient::Key checkKey 
= keyFromCreds(sample
, 4); 
1170                         if(common().validateKey(checkKey
)) { 
1174                         // ignore all problems in keyFromCreds 
1175                         secinfo("integrity", "%p caught error", this); 
1182     // out of options - credentials don't match 
1186 uint32_t KeychainDatabase::interactiveUnlockAttempts 
= 0; 
1188 // This does UI so needs the UI lock. It also interacts with the common, so needs the common lock. But can't have both at once! 
1189 // Try to hold the UI lock for the smallest amount of time possible while having the common lock where needed. 
1190 bool KeychainDatabase::interactiveUnlock() 
1192         secinfo("KCdb", "%p attempting interactive unlock", this); 
1193     interactiveUnlockAttempts
++; 
1195         SecurityAgent::Reason reason 
= SecurityAgent::noReason
; 
1196     QueryUnlock 
query(*this); 
1199                 query
.inferHints(Server::process()); 
1200         StSyncLock
<Mutex
, Mutex
> uisync(common().uiLock(), common()); 
1203         if (mSaveSecret 
&& reason 
== SecurityAgent::noReason
) { 
1204             query
.retrievePassword(mSecret
); 
1208                 secinfo("KCdb", "%p was unlocked during uiLock delay", this); 
1211     if (common().isLoginKeychain()) { 
1212         bool locked 
= false; 
1213         service_context_t context 
= common().session().get_current_service_context(); 
1214         if ((service_client_kb_is_locked(&context
, &locked
, NULL
) == 0) && locked
) { 
1215             QueryKeybagNewPassphrase 
keybagQuery(common().session()); 
1216             keybagQuery
.inferHints(Server::process()); 
1217             CssmAutoData 
pass(Allocator::standard(Allocator::sensitive
)); 
1218             CssmAutoData 
oldPass(Allocator::standard(Allocator::sensitive
)); 
1219             StSyncLock
<Mutex
, Mutex
> uisync(common().uiLock(), common()); 
1220             SecurityAgent::Reason queryReason 
= keybagQuery
.query(oldPass
, pass
); 
1222             if (queryReason 
== SecurityAgent::noReason
) { 
1223                 service_client_kb_change_secret(&context
, oldPass
.data(), (int)oldPass
.length(), pass
.data(), (int)pass
.length()); 
1224             } else if (queryReason 
== SecurityAgent::resettingPassword
) { 
1225                 query
.retrievePassword(pass
); 
1226                 service_client_kb_reset(&context
, pass
.data(), (int)pass
.length()); 
1232     return reason 
== SecurityAgent::noReason
; 
1235 uint32_t KeychainDatabase::getInteractiveUnlockAttempts() { 
1236     if (csr_check(CSR_ALLOW_APPLE_INTERNAL
)) { 
1237         // Not an internal install; don't answer 
1240         return interactiveUnlockAttempts
; 
1246 // Same thing, but obtain a new secret somehow and set it into the common. 
1248 bool KeychainDatabase::establishNewSecrets(const AccessCredentials 
*creds
, SecurityAgent::Reason reason
, bool change
) 
1250         list
<CssmSample
> samples
; 
1251         if (creds 
&& creds
->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK
, samples
)) { 
1252                 for (list
<CssmSample
>::iterator it 
= samples
.begin(); it 
!= samples
.end(); it
++) { 
1253                         TypedList 
&sample 
= *it
; 
1254                         sample
.checkProper(); 
1255                         switch (sample
.type()) { 
1256                         // interactively prompt the user 
1257                         case CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT
: 
1259                     secinfo("KCdb", "%p specified interactive passphrase", this); 
1260                     QueryNewPassphrase 
query(*this, reason
); 
1261                     StSyncLock
<Mutex
, Mutex
> uisync(common().uiLock(), common()); 
1262                     query
.inferHints(Server::process()); 
1263                     CssmAutoData 
passphrase(Allocator::standard(Allocator::sensitive
)); 
1264                     CssmAutoData 
oldPassphrase(Allocator::standard(Allocator::sensitive
)); 
1265                     SecurityAgent::Reason 
reason(query(oldPassphrase
, passphrase
)); 
1267                     if (reason 
== SecurityAgent::noReason
) { 
1268                         common().setup(NULL
, passphrase
); 
1269                         change_secret_on_keybag(*this, oldPassphrase
.data(), (int)oldPassphrase
.length(), passphrase
.data(), (int)passphrase
.length()); 
1274                         // try to use an explicitly given passphrase 
1275                         case CSSM_SAMPLE_TYPE_PASSWORD
: 
1277                     secinfo("KCdb", "%p specified explicit passphrase", this); 
1278                     if (sample
.length() != 2) 
1279                         CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
); 
1280                     if (common().isLoginKeychain()) { 
1281                         CssmAutoData 
oldPassphrase(Allocator::standard(Allocator::sensitive
)); 
1282                         list
<CssmSample
> oldSamples
; 
1283                         creds
->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK
, oldSamples
); 
1284                         for (list
<CssmSample
>::iterator oit 
= oldSamples
.begin(); oit 
!= oldSamples
.end(); oit
++) { 
1285                             TypedList 
&tmpList 
= *oit
; 
1286                             tmpList
.checkProper(); 
1287                             if (tmpList
.type() == CSSM_SAMPLE_TYPE_PASSWORD
) { 
1288                                 if (tmpList
.length() == 2) { 
1289                                     oldPassphrase 
= tmpList
[1].data(); 
1293                         if (!oldPassphrase
.length() && mSecret 
&& mSecret
.length()) { 
1294                             oldPassphrase 
= mSecret
; 
1296                         if ((oldPassphrase
.length() == sample
[1].data().length()) && 
1297                             !memcmp(oldPassphrase
.data(), sample
[1].data().data(), oldPassphrase
.length()) && 
1298                             oldPassphrase
.length()) { 
1299                             // don't change master key if the passwords are the same 
1302                         common().setup(NULL
, sample
[1]); 
1303                         change_secret_on_keybag(*this, oldPassphrase
.data(), (int)oldPassphrase
.length(), sample
[1].data().data(), (int)sample
[1].data().length()); 
1306                         common().setup(NULL
, sample
[1]); 
1310                         // try to open with a given master key 
1311                         case CSSM_WORDID_SYMMETRIC_KEY
: 
1312                         case CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY
: 
1313                                 secinfo("KCdb", "%p specified explicit master key", this); 
1314                                 common().setup(NULL
, keyFromCreds(sample
, 3)); 
1316                         // explicitly defeat the default action but don't try anything in particular 
1317                         case CSSM_WORDID_CANCELED
: 
1318                                 secinfo("KCdb", "%p defeat default action", this); 
1321                                 // Unknown sub-sample for acquiring new secret. 
1322                                 // If we wanted to be fascist, we could now do 
1323                                 //  CssmError::throwMe(CSSM_ERRCODE_SAMPLE_VALUE_NOT_SUPPORTED); 
1324                                 // But instead we try to be tolerant and continue on. 
1325                                 // This DOES however count as an explicit attempt at specifying unlock, 
1326                                 // so we will no longer try the default case below... 
1327                                 secinfo("KCdb", "%p unknown sub-sample acquisition (%d) ignored", 
1328                                         this, sample
.type()); 
1333                 // default action -- interactive (only) 
1334                 QueryNewPassphrase 
query(*this, reason
); 
1335                 StSyncLock
<Mutex
, Mutex
> uisync(common().uiLock(), common()); 
1336         query
.inferHints(Server::process()); 
1337                 CssmAutoData 
passphrase(Allocator::standard(Allocator::sensitive
)); 
1338         CssmAutoData 
oldPassphrase(Allocator::standard(Allocator::sensitive
)); 
1339         SecurityAgent::Reason 
reason(query(oldPassphrase
, passphrase
)); 
1341                 if (reason 
== SecurityAgent::noReason
) { 
1342             // If the DB was already unlocked then we have not yet checked the caller knows the old passphrase. Do so here. 
1343             if (change 
&& !validatePassphrase(oldPassphrase
.get())) { 
1344                 MacOSError::throwMe(errSecAuthFailed
); 
1346                         common().setup(NULL
, passphrase
); 
1347             change_secret_on_keybag(*this, oldPassphrase
.data(), (int)oldPassphrase
.length(), passphrase
.data(), (int)passphrase
.length()); 
1352         // out of options - no secret obtained 
1353         CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
); 
1358 // Given a (truncated) Database credentials TypedList specifying a master key, 
1359 // locate the key and return a reference to it. 
1361 CssmClient::Key 
KeychainDatabase::keyFromCreds(const TypedList 
&sample
, unsigned int requiredLength
) 
1363         // decode TypedList structure (sample type; Data:CSPHandle; Data:CSSM_KEY) 
1364         assert(sample
.type() == CSSM_SAMPLE_TYPE_SYMMETRIC_KEY 
|| sample
.type() == CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY
); 
1365         if (sample
.length() != requiredLength
 
1366                 || sample
[1].type() != CSSM_LIST_ELEMENT_DATUM
 
1367                 || sample
[2].type() != CSSM_LIST_ELEMENT_DATUM
 
1368                 || (requiredLength 
== 4 && sample
[3].type() != CSSM_LIST_ELEMENT_DATUM
)) 
1369                         CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
); 
1370         KeyHandle 
&handle 
= *sample
[1].data().interpretedAs
<KeyHandle
>(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
); 
1371     // We used to be able to check the length but supporting multiple client 
1372     // architectures dishes that (sizeof(CSSM_KEY) varies due to alignment and 
1373     // field-size differences).  The decoding in the transition layer should  
1374     // serve as a sufficient garbling check anyway.   
1375     if (sample
[2].data().data() == NULL
) 
1376         CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
); 
1377     CssmKey 
&key 
= *sample
[2].data().interpretedAs
<CssmKey
>(); 
1379         if (key
.header().cspGuid() == gGuidAppleCSPDL
) { 
1380                 // handleOrKey is a SecurityServer KeyHandle; ignore key argument 
1381                 return safer_cast
<LocalKey 
&>(*Server::key(handle
)); 
1383         if (sample
.type() == CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY
) { 
1385                         Contents (see DefaultCredentials::unlockKey in libsecurity_keychain/defaultcreds.cpp) 
1387                         sample[0]       sample type 
1388                         sample[1]       csp handle for master or wrapping key; is really a keyhandle 
1389                         sample[2]       masterKey [not used since securityd cannot interpret; use sample[1] handle instead] 
1390                         sample[3]       UnlockReferralRecord data, in this case the flattened symmetric key 
1393                 // RefPointer<Key> Server::key(KeyHandle key) 
1394                 KeyHandle keyhandle 
= *sample
[1].data().interpretedAs
<KeyHandle
>(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
); 
1395                 CssmData 
&flattenedKey 
= sample
[3].data(); 
1396                 RefPointer
<Key
> unwrappingKey 
= Server::key(keyhandle
); 
1397                 Database 
&db
=unwrappingKey
->database(); 
1399                 CssmKey rawWrappedKey
; 
1400                 unflattenKey(flattenedKey
, rawWrappedKey
); 
1402                 RefPointer
<Key
> masterKey
; 
1403                 CssmData emptyDescriptiveData
; 
1404                 const AccessCredentials 
*cred 
= NULL
; 
1405                 const AclEntryPrototype 
*owner 
= NULL
; 
1406                 CSSM_KEYUSE usage 
= CSSM_KEYUSE_ANY
; 
1407                 CSSM_KEYATTR_FLAGS attrs 
= CSSM_KEYATTR_EXTRACTABLE
;    //CSSM_KEYATTR_RETURN_REF |  
1409                 // Get default credentials for unwrappingKey (the one on the token) 
1410                 // Copied from Statics::Statics() in libsecurity_keychain/aclclient.cpp 
1411                 // Following KeyItem::getCredentials, one sees that the "operation" parameter 
1412                 // e.g. "CSSM_ACL_AUTHORIZATION_DECRYPT" is ignored 
1413                 Allocator 
&alloc 
= Allocator::standard(); 
1414                 AutoCredentials 
promptCred(alloc
, 3);// enable interactive prompting 
1416                 // promptCred: a credential permitting user prompt confirmations 
1418                 //  a KEYCHAIN_PROMPT sample, both by itself and in a THRESHOLD 
1419                 //  a PROMPTED_PASSWORD sample 
1420                 promptCred
.sample(0) = TypedList(alloc
, CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT
); 
1421                 promptCred
.sample(1) = TypedList(alloc
, CSSM_SAMPLE_TYPE_THRESHOLD
, 
1422                         new(alloc
) ListElement(TypedList(alloc
, CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT
))); 
1423                 promptCred
.sample(2) = TypedList(alloc
, CSSM_SAMPLE_TYPE_PROMPTED_PASSWORD
, 
1424                         new(alloc
) ListElement(alloc
, CssmData())); 
1426                 // This unwrap object is here just to provide a context 
1427                 CssmClient::UnwrapKey 
unwrap(Server::csp(), CSSM_ALGID_NONE
);   //ok to lie about csp here 
1428                 unwrap
.mode(CSSM_ALGMODE_NONE
); 
1429                 unwrap
.padding(CSSM_PADDING_PKCS1
); 
1430                 unwrap
.cred(promptCred
); 
1431                 unwrap
.add(CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT
, uint32(CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7
)); 
1432                 Security::Context 
*tmpContext
; 
1433                 CSSM_CC_HANDLE CCHandle 
= unwrap
.handle(); 
1434                 /*CSSM_RETURN rx = */ CSSM_GetContext (CCHandle
, (CSSM_CONTEXT_PTR 
*)&tmpContext
); 
1436                 // OK, this is skanky but necessary. We overwrite fields in the context struct 
1438                 tmpContext
->ContextType 
= CSSM_ALGCLASS_ASYMMETRIC
; 
1439                 tmpContext
->AlgorithmType 
= CSSM_ALGID_RSA
; 
1441                 db
.unwrapKey(*tmpContext
, cred
, owner
, unwrappingKey
, NULL
, usage
, attrs
, 
1442                         rawWrappedKey
, masterKey
, emptyDescriptiveData
); 
1444             Allocator::standard().free(rawWrappedKey
.KeyData
.Data
); 
1446                 return safer_cast
<LocalKey 
&>(*masterKey
).key(); 
1448         else if (sample
.type() == CSSM_SAMPLE_TYPE_SYMMETRIC_KEY 
&& sample
.length() == 4 && sample
[3].data().length() > 0) { 
1450          Contents (see MasterKeyUnlockCredentials in libsecurity_cdsa_client/lib/aclclient.cpp) 
1452          sample[0]  sample type 
1453          sample[1]  0, since we don't have a valid handle 
1454          sample[2]  CssmKey of the masterKey [can't immediately use since it includes a CSSM_DATA struct with pointers] 
1455          sample[3]  flattened symmetric master key, including the key data 
1458         // Fix up key to include actual data 
1459         CssmData 
&flattenedKey 
= sample
[3].data(); 
1460         unflattenKey(flattenedKey
, key
); 
1462         // Check that we have a reasonable key 
1463         if (key
.header().blobType() != CSSM_KEYBLOB_RAW
) { 
1464             CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE
); 
1466         if (key
.header().keyClass() != CSSM_KEYCLASS_SESSION_KEY
) { 
1467             CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS
); 
1470         // bring the key into the CSP and return it 
1471         return CssmClient::Key(Server::csp(), key
, true); 
1473                 // not a KeyHandle reference; use key as a raw key 
1474                 if (key
.header().blobType() != CSSM_KEYBLOB_RAW
) 
1475                         CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE
); 
1476                 if (key
.header().keyClass() != CSSM_KEYCLASS_SESSION_KEY
) 
1477                         CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS
); 
1478                 return CssmClient::Key(Server::csp(), key
, true); 
1482 void unflattenKey(const CssmData 
&flatKey
, CssmKey 
&rawKey
) 
1484     // The format we're expecting is a CSSM_KEY followed by the actual key data: 
1485     //    CSSM_KEY : KEY DATA 
1486     // which is approximately: 
1487     //    h2ni(CSSM_KEYHEADER) : 4 bytes padding : CSSM_DATA{?:?} : KEY BYTES 
1489     // Note that CSSM_KEY includes a CSSM_DATA struct, which we will ignore as it has pointers. 
1490     // The pointer and length will be set to whatever key data follows the CSSM_KEY in rawKey. 
1492         // unflatten the raw input key naively: key header then key data 
1493         // We also convert it back to host byte order 
1494         // A CSSM_KEY is a CSSM_KEYHEADER followed by a CSSM_DATA 
1496         // Now copy: header, then key struct, then key data 
1497         memcpy(&rawKey
.KeyHeader
, flatKey
.Data
, sizeof(CSSM_KEYHEADER
)); 
1498         memcpy(&rawKey
.KeyData
, flatKey
.Data 
+ sizeof(CSSM_KEYHEADER
), sizeof(CSSM_DATA
)); 
1499         size_t keyDataLength 
= flatKey
.length() - sizeof(CSSM_KEY
); 
1500         rawKey
.KeyData
.Data 
= Allocator::standard().malloc
<uint8
>(keyDataLength
); 
1501         rawKey
.KeyData
.Length 
= keyDataLength
; 
1502         memcpy(rawKey
.KeyData
.Data
, flatKey
.Data 
+ sizeof(CSSM_KEY
), keyDataLength
); 
1503         Security::n2hi(rawKey
.KeyHeader
);       // convert it to host byte order 
1507 KeychainDatabase::keyFromKeybag(const TypedList 
&sample
) 
1509     service_context_t context
; 
1510     uint8_t *session_key
; 
1511     int session_key_size
; 
1513     const struct ccmode_siv 
*mode 
= ccaes_siv_decrypt_mode(); 
1514     const size_t session_key_wrapped_len 
= 40; 
1515     const size_t version_len 
= 1, nonce_len 
= 16; 
1516     uint8_t *decrypted_data
; 
1517     size_t decrypted_len
; 
1519     assert(sample
.type() == CSSM_SAMPLE_TYPE_KEYBAG_KEY
); 
1521     CssmData 
&unlock_token 
= sample
[2].data(); 
1523     context 
= common().session().get_current_service_context(); 
1524     rc 
= service_client_kb_unwrap_key(&context
, unlock_token
.data(), session_key_wrapped_len
, key_class_ak
, (void **)&session_key
, &session_key_size
); 
1526         CssmError::throwMe(CSSM_ERRCODE_INVALID_CRYPTO_DATA
); 
1529     uint8_t *indata 
= (uint8_t *)unlock_token
.data() + session_key_wrapped_len
; 
1530     size_t inlen 
= unlock_token
.length() - session_key_wrapped_len
; 
1532     decrypted_len 
= ccsiv_plaintext_size(mode
, inlen 
- (version_len 
+ nonce_len
)); 
1533     decrypted_data 
= (uint8_t *)calloc(1, decrypted_len
); 
1535     ccsiv_ctx_decl(mode
->size
, ctx
); 
1537     rc 
= ccsiv_init(mode
, ctx
, session_key_size
, session_key
); 
1538     if (rc 
!= 0) CssmError::throwMe(CSSM_ERRCODE_INVALID_CRYPTO_DATA
); 
1539     rc 
= ccsiv_set_nonce(mode
, ctx
, nonce_len
, indata 
+ version_len
); 
1540     if (rc 
!= 0) CssmError::throwMe(CSSM_ERRCODE_INVALID_CRYPTO_DATA
); 
1541     rc 
= ccsiv_aad(mode
, ctx
, 1, indata
); 
1542     if (rc 
!= 0) CssmError::throwMe(CSSM_ERRCODE_INVALID_CRYPTO_DATA
); 
1543     rc 
= ccsiv_crypt(mode
, ctx
, inlen 
- (version_len 
+ nonce_len
), indata 
+ version_len 
+ nonce_len
, decrypted_data
); 
1544     if (rc 
!= 0) CssmError::throwMe(CSSM_ERRCODE_INVALID_CRYPTO_DATA
); 
1546     ccsiv_ctx_clear(mode
->size
, ctx
); 
1548     //free(decrypted_data); 
1550     return makeRawKey(decrypted_data
, decrypted_len
, CSSM_ALGID_3DES_3KEY_EDE
, CSSM_KEYUSE_ENCRYPT 
| CSSM_KEYUSE_DECRYPT
); 
1553 // adapted from DatabaseCryptoCore::makeRawKey 
1554 CssmClient::Key 
KeychainDatabase::makeRawKey(void *data
, size_t length
, 
1555     CSSM_ALGORITHMS algid
, CSSM_KEYUSE usage
) 
1559     key
.header().BlobType 
= CSSM_KEYBLOB_RAW
; 
1560     key
.header().Format 
= CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING
; 
1561     key
.header().AlgorithmId 
= algid
; 
1562     key
.header().KeyClass 
= CSSM_KEYCLASS_SESSION_KEY
; 
1563     key
.header().KeyUsage 
= usage
; 
1564     key
.header().KeyAttr 
= 0; 
1565     key
.KeyData 
= CssmData(data
, length
); 
1567     // unwrap it into the CSP (but keep it raw) 
1568     CssmClient::UnwrapKey 
unwrap(Server::csp(), CSSM_ALGID_NONE
); 
1569     CssmKey unwrappedKey
; 
1570     CssmData descriptiveData
; 
1572         CssmClient::KeySpec(CSSM_KEYUSE_ANY
, CSSM_KEYATTR_RETURN_DATA 
| CSSM_KEYATTR_EXTRACTABLE
), 
1573         unwrappedKey
, &descriptiveData
, NULL
); 
1574     return CssmClient::Key(Server::csp(), unwrappedKey
); 
1578 // Verify a putative database passphrase. 
1579 // If the database is already unlocked, just check the passphrase. 
1580 // Otherwise, unlock with that passphrase and report success. 
1581 // Caller must hold the common lock. 
1583 bool KeychainDatabase::validatePassphrase(const CssmData 
&passphrase
) const 
1585         if (common().hasMaster()) { 
1586                 // verify against known secret 
1587                 return common().validatePassphrase(passphrase
); 
1589                 // no master secret - perform "blind" unlock to avoid actual unlock 
1591                         DatabaseCryptoCore test
; 
1592                         test
.setup(mBlob
, passphrase
); 
1593                         test
.decodeCore(mBlob
, NULL
); 
1603 // Lock this database 
1605 void KeychainDatabase::lockDb() 
1612 // Given a Key for this database, encode it into a blob and return it. 
1614 KeyBlob 
*KeychainDatabase::encodeKey(const CssmKey 
&key
, const CssmData 
&pubAcl
, const CssmData 
&privAcl
) 
1616         bool inTheClear 
= false; 
1617         if((key
.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY
) && 
1618            !(key
.attribute(CSSM_KEYATTR_PUBLIC_KEY_ENCRYPT
))) { 
1621         StLock
<Mutex
> _(common()); 
1623                 makeUnlocked(false); 
1625     // tell the cryptocore to form the key blob 
1626     return common().encodeKeyCore(key
, pubAcl
, privAcl
, inTheClear
); 
1631 // Given a "blobbed" key for this database, decode it into its real 
1632 // key object and (re)populate its ACL. 
1634 void KeychainDatabase::decodeKey(KeyBlob 
*blob
, CssmKey 
&key
, void * &pubAcl
, void * &privAcl
) 
1636         StLock
<Mutex
> _(common()); 
1638         if(!blob
->isClearText()) 
1639                 makeUnlocked(false);                                                    // we need our keys 
1641         common().decodeKeyCore(blob
, key
, pubAcl
, privAcl
); 
1642         // memory protocol: pubAcl points into blob; privAcl was allocated 
1648 // Given a KeychainKey (that implicitly belongs to another keychain),  
1649 // return it encoded using this keychain's operational secrets.   
1651 KeyBlob 
*KeychainDatabase::recodeKey(KeychainKey 
&oldKey
) 
1653         if (mRecodingSource 
!= &oldKey
.referent
<KeychainDatabase
>()) { 
1654         CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
); 
1657     // To protect this operation, we need to take the mutex for both our common and the remote key's common in some defined order. 
1658     // Grab the common being cloned (oldKey's) first, and then the common receiving the recoding (ours). 
1659     StLock
<Mutex
> _ (oldKey
.referent
<KeychainDatabase
>().common()); 
1660     StLock
<Mutex
> __(common()); 
1662         oldKey
.instantiateAcl();        // make sure key is decoded 
1663         CssmData publicAcl
, privateAcl
; 
1664         oldKey
.exportBlob(publicAcl
, privateAcl
); 
1665         // NB: blob's memory belongs to caller, not the common 
1668          * Make sure the new key is in the same cleartext/encrypted state. 
1670         bool inTheClear 
= false; 
1671         assert(oldKey
.blob()); 
1672         if(oldKey
.blob() && oldKey
.blob()->isClearText()) { 
1676         KeyBlob 
*blob 
= common().encodeKeyCore(oldKey
.cssmKey(), publicAcl
, privateAcl
, inTheClear
); 
1677         oldKey
.acl().allocator
.free(publicAcl
); 
1678         oldKey
.acl().allocator
.free(privateAcl
); 
1684 // Modify database parameters 
1686 void KeychainDatabase::setParameters(const DBParameters 
¶ms
) 
1688         StLock
<Mutex
> _(common()); 
1689     makeUnlocked(false); 
1690         common().mParams 
= params
; 
1691     common().invalidateBlob();          // invalidate old blobs 
1692     activity();                         // (also resets the timeout timer) 
1693         secinfo("KCdb", "%p common %p(%s) set params=(%u,%u)", 
1694                 this, &common(), dbName(), params
.idleTimeout
, params
.lockOnSleep
); 
1699 // Retrieve database parameters 
1701 void KeychainDatabase::getParameters(DBParameters 
¶ms
) 
1703         StLock
<Mutex
> _(common()); 
1704     makeUnlocked(false); 
1705         params 
= common().mParams
; 
1706     //activity();               // getting parameters does not reset the idle timer 
1711 // RIGHT NOW, database ACLs are attached to the database. 
1712 // This will soon move upstairs. 
1714 SecurityServerAcl 
&KeychainDatabase::acl() 
1721 // Intercept ACL change requests and reset blob validity 
1723 void KeychainDatabase::instantiateAcl() 
1725         StLock
<Mutex
> _(common()); 
1726         makeUnlocked(false); 
1729 void KeychainDatabase::changedAcl() 
1731         StLock
<Mutex
> _(common()); 
1737 // Check an incoming DbBlob for basic viability 
1739 void KeychainDatabase::validateBlob(const DbBlob 
*blob
) 
1741     // perform basic validation on the blob 
1743         blob
->validate(CSSMERR_APPLEDL_INVALID_DATABASE_BLOB
); 
1744         if (blob
->startCryptoBlob 
> blob
->totalLength
) { 
1745                 CssmError::throwMe(CSSMERR_APPLEDL_INVALID_DATABASE_BLOB
); 
1747         switch (blob
->version()) { 
1748 #if defined(COMPAT_OSX_10_0) 
1749                 case DbBlob::version_MacOS_10_0
: 
1752                 case DbBlob::version_MacOS_10_1
: 
1754                 case DbBlob::version_partition
: 
1757                         CssmError::throwMe(CSSMERR_APPLEDL_INCOMPATIBLE_DATABASE_BLOB
); 
1762 // Check if this database is currently recoding 
1764 bool KeychainDatabase::isRecoding() 
1766     secnotice("integrity", "recoding source: %p", mRecodingSource
.get()); 
1767     return (mRecodingSource
.get() != NULL 
|| mRecoded
); 
1771 // Mark ourselves as no longer recoding 
1773 void KeychainDatabase::recodeFinished() 
1775     secnotice("integrity", "recoding finished"); 
1776     mRecodingSource 
= NULL
; 
1782 // Debugging support 
1784 #if defined(DEBUGDUMP) 
1786 void KeychainDbCommon::dumpNode() 
1788         PerSession::dumpNode(); 
1789         uint32 sig
; memcpy(&sig
, &mIdentifier
.signature(), sizeof(sig
)); 
1790         Debug::dump(" %s[%8.8x]", mIdentifier
.dbName(), sig
); 
1792                 Debug::dump(" locked"); 
1794                 time_t whenTime 
= time_t(when()); 
1795                 Debug::dump(" unlocked(%24.24s/%.2g)", ctime(&whenTime
), 
1796                         (when() - Time::now()).seconds()); 
1798         Debug::dump(" params=(%u,%u)", mParams
.idleTimeout
, mParams
.lockOnSleep
); 
1801 void KeychainDatabase::dumpNode() 
1803         PerProcess::dumpNode(); 
1804         Debug::dump(" %s vers=%u", 
1805                 mValidData 
? " data" : " nodata", version
); 
1807                 uint32 sig
; memcpy(&sig
, &mBlob
->randomSignature
, sizeof(sig
)); 
1808                 Debug::dump(" blob=%p[%8.8x]", mBlob
, sig
); 
1810                 Debug::dump(" noblob"); 
1818 // DbCommon basic features 
1820 KeychainDbCommon::KeychainDbCommon(Session 
&ssn
, const DbIdentifier 
&id
, uint32 requestedVersion
) 
1821         : LocalDbCommon(ssn
), DatabaseCryptoCore(requestedVersion
), sequence(0), version(1), mIdentifier(id
), 
1822       mIsLocked(true), mValidParams(false), mLoginKeychain(false) 
1824     // match existing DbGlobal or create a new one 
1826         Server 
&server 
= Server::active(); 
1827         StLock
<Mutex
> _(server
); 
1828         if (KeychainDbGlobal 
*dbglobal 
= 
1829                 server
.findFirst
<KeychainDbGlobal
, const DbIdentifier 
&>(&KeychainDbGlobal::identifier
, identifier())) { 
1831             secinfo("KCdb", "%p linking to existing DbGlobal %p", this, dbglobal
); 
1833             // DbGlobal not present; make a new one 
1834             parent(*new KeychainDbGlobal(identifier())); 
1835             secinfo("KCdb", "%p linking to new DbGlobal %p", this, &global()); 
1838         // link lifetime to the Session 
1839         session().addReference(*this); 
1841         if (strcasestr(id
.dbName(), "login.keychain") != NULL
) { 
1842             mLoginKeychain 
= true; 
1847 void KeychainDbCommon::initializeKeybag() { 
1848     if (mLoginKeychain 
&& !session().keybagGetState(session_keybag_loaded
)) { 
1849         service_context_t context 
= session().get_current_service_context(); 
1850         if (service_client_kb_load(&context
) == 0) { 
1851             session().keybagSetState(session_keybag_loaded
); 
1856 KeychainDbCommon::KeychainDbCommon(Session 
&ssn
, const DbIdentifier 
&id
, KeychainDbCommon
& toClone
) 
1857     : LocalDbCommon(ssn
), DatabaseCryptoCore(toClone
.mBlobVersion
), sequence(toClone
.sequence
), mParams(toClone
.mParams
), version(toClone
.version
), 
1858     mIdentifier(id
), mIsLocked(toClone
.mIsLocked
), mValidParams(toClone
.mValidParams
), mLoginKeychain(toClone
.mLoginKeychain
) 
1863         Server 
&server 
= Server::active(); 
1864         StLock
<Mutex
> _(server
); 
1865         if (KeychainDbGlobal 
*dbglobal 
= 
1866             server
.findFirst
<KeychainDbGlobal
, const DbIdentifier 
&>(&KeychainDbGlobal::identifier
, identifier())) { 
1868             secinfo("KCdb", "%p linking to existing DbGlobal %p", this, dbglobal
); 
1870             // DbGlobal not present; make a new one 
1871             parent(*new KeychainDbGlobal(identifier())); 
1872             secinfo("KCdb", "%p linking to new DbGlobal %p", this, &global()); 
1874         session().addReference(*this); 
1878 KeychainDbCommon::~KeychainDbCommon() 
1880     secinfo("KCdb", "releasing keychain %p %s", this, (char*)this->dbName()); 
1882         // explicitly unschedule ourselves 
1883         Server::active().clearTimer(this); 
1884     if (mLoginKeychain
) { 
1885         session().keybagClearState(session_keybag_unlocked
); 
1887     // remove ourselves from mCommonSet 
1891 void KeychainDbCommon::cloneFrom(KeychainDbCommon
& toClone
, uint32 requestedVersion
) { 
1892     // don't clone the mIdentifier 
1893     sequence 
= toClone
.sequence
; 
1894     mParams 
= toClone
.mParams
; 
1895     version 
= toClone
.version
; 
1896     mIsLocked 
= toClone
.mIsLocked
; 
1897     mValidParams 
= toClone
.mValidParams
; 
1898     mLoginKeychain 
= toClone
.mLoginKeychain
; 
1900     DatabaseCryptoCore::initializeFrom(toClone
, requestedVersion
); 
1903 void KeychainDbCommon::kill() 
1905     StReadWriteLock 
_(mRWCommonLock
, StReadWriteLock::Write
); 
1906     mCommonSet
.erase(this); 
1909 KeychainDbGlobal 
&KeychainDbCommon::global() const 
1911         return parent
<KeychainDbGlobal
>(); 
1915 void KeychainDbCommon::select() 
1918 void KeychainDbCommon::unselect() 
1923 void KeychainDbCommon::makeNewSecrets() 
1925         // we already have a master key (right?) 
1926         assert(hasMaster()); 
1928         // tell crypto core to generate the use keys 
1929         DatabaseCryptoCore::generateNewSecrets(); 
1931         // we're now officially "unlocked"; set the timer 
1937 // All unlocking activity ultimately funnels through this method. 
1938 // This unlocks a DbCommon using the secrets setup in its crypto core 
1939 // component, and performs all the housekeeping needed to represent 
1940 // the state change. 
1941 // Returns true if unlock was successful, false if it failed due to 
1942 // invalid/insufficient secrets. Throws on other errors. 
1944 bool KeychainDbCommon::unlockDb(DbBlob 
*blob
, void **privateAclBlob
) 
1947                 // Tell the cryptocore to (try to) decode itself. This will fail 
1948                 // in an astonishing variety of ways if the passphrase is wrong. 
1949                 assert(hasMaster()); 
1950                 decodeCore(blob
, privateAclBlob
); 
1951                 secinfo("KCdb", "%p unlock successful", this); 
1953                 secinfo("KCdb", "%p unlock failed", this); 
1957         // get the database parameters only if we haven't got them yet 
1958         if (!mValidParams
) { 
1959                 mParams 
= blob
->params
; 
1960                 n2hi(mParams
.idleTimeout
); 
1961                 mValidParams 
= true;    // sticky 
1964         bool isLocked 
= mIsLocked
; 
1966         setUnlocked();          // mark unlocked 
1969                 // broadcast unlock notification, but only if we were previously locked 
1970                 notify(kNotificationEventUnlocked
); 
1971         secinfo("KCdb", "unlocking keychain %p %s", this, (char*)this->dbName()); 
1976 void KeychainDbCommon::setUnlocked() 
1978         session().addReference(*this);  // active/held 
1979         mIsLocked 
= false;                              // mark unlocked 
1980         activity();                                             // set timeout timer 
1984 void KeychainDbCommon::lockDb() 
1987         StLock
<Mutex
> _(*this); 
1989             DatabaseCryptoCore::invalidate(); 
1990             notify(kNotificationEventLocked
); 
1991             secinfo("KCdb", "locking keychain %p %s", this, (char*)this->dbName()); 
1992             Server::active().clearTimer(this); 
1994             mIsLocked 
= true;           // mark locked 
1996             // this call may destroy us if we have no databases anymore 
1997             session().removeReference(*this); 
2003 DbBlob 
*KeychainDbCommon::encode(KeychainDatabase 
&db
) 
2005     assert(!isLocked());        // must have been unlocked by caller 
2007     // export database ACL to blob form 
2008     CssmData pubAcl
, privAcl
; 
2009     db
.acl().exportBlob(pubAcl
, privAcl
); 
2011     // tell the cryptocore to form the blob 
2013     form
.randomSignature 
= identifier(); 
2014     form
.sequence 
= sequence
; 
2015     form
.params 
= mParams
; 
2016         h2ni(form
.params
.idleTimeout
); 
2018         assert(hasMaster()); 
2019     DbBlob 
*blob 
= encodeCore(form
, pubAcl
, privAcl
); 
2022     db
.acl().allocator
.free(pubAcl
); 
2023     db
.acl().allocator
.free(privAcl
); 
2029 // Perform deferred lock processing for a database. 
2031 void KeychainDbCommon::action() 
2033         secinfo("KCdb", "common %s(%p) locked by timer", dbName(), this); 
2037 void KeychainDbCommon::activity() 
2040                 secinfo("KCdb", "setting DbCommon %p timer to %d", 
2041                         this, int(mParams
.idleTimeout
)); 
2042                 Server::active().setTimer(this, Time::Interval(int(mParams
.idleTimeout
))); 
2046 void KeychainDbCommon::sleepProcessing() 
2048         secinfo("KCdb", "common %s(%p) sleep-lock processing", dbName(), this); 
2049     if (mParams
.lockOnSleep 
&& !isDefaultSystemKeychain()) { 
2050         StLock
<Mutex
> _(*this); 
2055 void KeychainDbCommon::lockProcessing() 
2062 // We consider a keychain to belong to the system domain if it resides 
2063 // in /Library/Keychains. That's not exactly fool-proof, but we don't 
2064 // currently have any internal markers to interrogate. 
2066 bool KeychainDbCommon::belongsToSystem() const 
2068     if (const char *name 
= this->dbName()) 
2069         return !strncmp(name
, "/Library/Keychains/", 19); 
2073 bool KeychainDbCommon::isDefaultSystemKeychain() const 
2075     // /Library/Keychains/System.keychain (34) 
2076     if (const char *name 
= this->dbName()) 
2077         return !strncmp(name
, "/Library/Keychains/System.keychain", 34); 
2082 // Keychain global objects 
2084 KeychainDbGlobal::KeychainDbGlobal(const DbIdentifier 
&id
) 
2089 KeychainDbGlobal::~KeychainDbGlobal() 
2091         secinfo("KCdb", "DbGlobal %p destroyed", this);