/ securityd / src / kcdatabase.cpp
kcdatabase.cpp
   1  /*
   2   * Copyright (c) 2000-2009,2012-2014 Apple Inc. All Rights Reserved.
   3   * 
   4   * @APPLE_LICENSE_HEADER_START@
   5   * 
   6   * This file contains Original Code and/or Modifications of Original Code
   7   * as defined in and that are subject to the Apple Public Source License
   8   * Version 2.0 (the 'License'). You may not use this file except in
   9   * compliance with the License. Please obtain a copy of the License at
  10   * http://www.opensource.apple.com/apsl/ and read it before using this
  11   * file.
  12   * 
  13   * The Original Code and all software distributed under the License are
  14   * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  15   * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  16   * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
  17   * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  18   * Please see the License for the specific language governing rights and
  19   * limitations under the License.
  20   * 
  21   * @APPLE_LICENSE_HEADER_END@
  22   */
  23  
  24  
  25  //
  26  // kcdatabase - software database container implementation.
  27  //
  28  // General implementation notes:
  29  // This leverages LocalDatabase/LocalKey for cryptography, and adds the
  30  //  storage coder/decoder logic that implements "keychain" databases in their
  31  //  intricately choreographed dance between securityd and the AppleCSPDL.
  32  // As always, Database objects are lifetime-bound to their Process referent;
  33  //  they can also be destroyed explicitly with a client release call.
  34  // DbCommons are reference-held by their Databases, with one extra special
  35  //  reference (from the Session) introduced when the database unlocks, and
  36  //  removed when it locks again. That way, an unused DbCommon dies when it
  37  //  is locked or when the Session dies, whichever happens earlier.
  38  // There is (as yet) no global-scope Database object for Keychain databases.
  39  //
  40  
  41  #define __STDC_WANT_LIB_EXT1__ 1
  42  #include <string.h>
  43  
  44  #include "kcdatabase.h"
  45  #include "agentquery.h"
  46  #include "kckey.h"
  47  #include "server.h"
  48  #include "session.h"
  49  #include "notifications.h"
  50  #include "SecRandom.h"
  51  #include "keychainstasherinterface.h"
  52  #include <vector>           // @@@  4003540 workaround
  53  #include <security_cdsa_utilities/acl_any.h>	// for default owner ACLs
  54  #include <security_cdsa_utilities/cssmendian.h>
  55  #include <security_cdsa_client/wrapkey.h>
  56  #include <security_cdsa_client/genkey.h>
  57  #include <security_cdsa_client/signclient.h>
  58  #include <security_cdsa_client/cryptoclient.h>
  59  #include <security_cdsa_client/macclient.h>
  60  #include <securityd_client/dictionary.h>
  61  #include <security_utilities/endian.h>
  62  #include <security_utilities/errors.h>
  63  #include "securityd_service/securityd_service/securityd_service_client.h"
  64  #include <AssertMacros.h>
  65  #include <syslog.h>
  66  #include <sys/sysctl.h>
  67  #include <sys/kauth.h>
  68  #include <sys/csr.h>
  69  __BEGIN_DECLS
  70  #include <corecrypto/ccmode_siv.h>
  71  __END_DECLS
  72  
  73  void unflattenKey(const CssmData &flatKey, CssmKey &rawKey);	//>> make static method on KeychainDatabase
  74  
  75  //
  76  // Static members
  77  //
  78  KeychainDbCommon::CommonSet KeychainDbCommon::mCommonSet;
  79  ReadWriteLock KeychainDbCommon::mRWCommonLock;
  80  
  81  // Process is using a cached effective uid, login window switches uid after the intial connection
  82  static void get_process_euid(pid_t pid, uid_t * out_euid)
  83  {
  84      if (!out_euid) return;
  85  
  86      struct kinfo_proc proc_info = {};
  87      int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
  88      size_t len = sizeof(struct kinfo_proc);
  89      int ret;
  90      ret = sysctl(mib, (sizeof(mib)/sizeof(int)), &proc_info, &len, NULL, 0);
  91  
  92      // don't allow root
  93      if ((ret == 0) && (proc_info.kp_eproc.e_ucred.cr_uid != 0)) {
  94          *out_euid = proc_info.kp_eproc.e_ucred.cr_uid;
  95      }
  96  }
  97  
  98  static int
  99  unlock_keybag(KeychainDatabase & db, const void * secret, int secret_len)
 100  {
 101      int rc = -1;
 102  
 103      if (!db.common().isLoginKeychain()) return 0;
 104  
 105      service_context_t context = db.common().session().get_current_service_context();
 106  
 107      // login window attempts to change the password before a session has a uid
 108      if (context.s_uid == AU_DEFAUDITID) {
 109          get_process_euid(db.process().pid(), &context.s_uid);
 110      }
 111  
 112      // try to unlock first if not found then load/create or unlock
 113      // loading should happen when the kb common object is created
 114      // if it doesn't exist yet then the unlock will fail and we'll create everything
 115      rc = service_client_kb_unlock(&context, secret, secret_len);
 116      if (rc == KB_BagNotLoaded) {
 117          if (service_client_kb_load(&context) == KB_BagNotFound) {
 118              rc = service_client_kb_create(&context, secret, secret_len);
 119          } else {
 120              rc = service_client_kb_unlock(&context, secret, secret_len);
 121          }
 122      }
 123  
 124      if (rc != 0) { // if we just upgraded make sure we swap the encryption key to the password
 125          if (!db.common().session().keybagGetState(session_keybag_check_master_key)) {
 126              CssmAutoData encKey(Allocator::standard(Allocator::sensitive));
 127              db.common().get_encryption_key(encKey);
 128              if ((rc = service_client_kb_unlock(&context, encKey.data(), (int)encKey.length())) == 0) {
 129                  rc = service_client_kb_change_secret(&context, encKey.data(), (int)encKey.length(), secret, secret_len);
 130              }
 131  
 132              if (rc != 0) { // if a login.keychain password exists but doesnt on the keybag update it
 133                  bool no_pin = false;
 134                  if ((secret_len > 0) && service_client_kb_is_locked(&context, NULL, &no_pin) == 0) {
 135                      if (no_pin) {
 136                          syslog(LOG_ERR, "Updating iCloud keychain passphrase for uid %d", context.s_uid);
 137                          service_client_kb_change_secret(&context, NULL, 0, secret, secret_len);
 138                      }
 139                  }
 140              }
 141          } // session_keybag_check_master_key
 142      }
 143  
 144      if (rc == 0) {
 145          db.common().session().keybagSetState(session_keybag_unlocked|session_keybag_loaded|session_keybag_check_master_key);
 146      } else {
 147          syslog(LOG_ERR, "Failed to unlock iCloud keychain for uid %d", context.s_uid);
 148      }
 149  
 150      return rc;
 151  }
 152  
 153  static void
 154  change_secret_on_keybag(KeychainDatabase & db, const void * secret, int secret_len, const void * new_secret, int new_secret_len)
 155  {
 156      if (!db.common().isLoginKeychain()) return;
 157  
 158      service_context_t context = db.common().session().get_current_service_context();
 159  
 160      // login window attempts to change the password before a session has a uid
 161      if (context.s_uid == AU_DEFAUDITID) {
 162          get_process_euid(db.process().pid(), &context.s_uid);
 163      }
 164  
 165      // if a login.keychain doesn't exist yet it comes into securityd as a create then change_secret
 166      // we need to create the keybag in this case if it doesn't exist
 167      int rc = service_client_kb_change_secret(&context, secret, secret_len, new_secret, new_secret_len);
 168      if (rc == KB_BagNotLoaded) {
 169          if (service_client_kb_load(&context) == KB_BagNotFound) {
 170              rc = service_client_kb_create(&context, new_secret, new_secret_len);
 171          } else {
 172              rc = service_client_kb_change_secret(&context, secret, secret_len, new_secret, new_secret_len);
 173          }
 174      }
 175  
 176      // this makes it possible to restore a deleted keybag on condition it still exists in kernel
 177      if (rc != KB_Success) {
 178          service_client_kb_save(&context);
 179      }
 180  
 181      // if for some reason we are locked lets unlock so later we don't try and throw up SecurityAgent dialog
 182      bool locked = false;
 183      if ((service_client_kb_is_locked(&context, &locked, NULL) == KB_Success) && locked) {
 184          rc = service_client_kb_unlock(&context, new_secret, new_secret_len);
 185          if (rc != KB_Success) {
 186              syslog(LOG_ERR, "Failed to unlock iCloud keychain for uid %d (%d)", context.s_uid, (int)rc);
 187          }
 188      }
 189  }
 190  
 191  // Attempt to unlock the keybag with a AccessCredentials password.
 192  // Honors UI disabled flags from clients set in the cred before prompt.
 193  static bool
 194  unlock_keybag_with_cred(KeychainDatabase &db, const AccessCredentials *cred){
 195      list<CssmSample> samples;
 196      if (cred && cred->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK, samples)) {
 197          for (list<CssmSample>::iterator it = samples.begin(); it != samples.end(); it++) {
 198              TypedList &sample = *it;
 199              sample.checkProper();
 200              switch (sample.type()) {
 201                  // interactively prompt the user - no additional data
 202                  case CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT:
 203                  {
 204                      /*
 205                       Okay, this is messy. We need to hold the common lock to be certain we're modifying the world
 206                       as we intend. But UI ^ common, and QueryKeybagPassphrase::query() has tons of side effects by necessity,
 207                       so just confirm that the operation did what we wanted after the fact.
 208                       */
 209                      bool query_success = false;
 210                      bool unlock_success = false;
 211                      bool looped = false;
 212                      do {
 213                          {
 214                              StSyncLock<Mutex, Mutex> uisync(db.common().uiLock(), db.common());
 215                              // Once we get the ui lock, check whether another thread has already unlocked keybag
 216                              bool locked = false;
 217                              query_success = false;
 218                              service_context_t context = db.common().session().get_current_service_context();
 219                              if ((service_client_kb_is_locked(&context, &locked, NULL) == 0) && locked) {
 220                                  QueryKeybagPassphrase keybagQuery(db.common().session(), 3);
 221                                  keybagQuery.inferHints(Server::process());
 222                                  if (keybagQuery.query() == SecurityAgent::noReason) {
 223                                      query_success = true;
 224                                  }
 225                              } else {
 226                                  // another thread already unlocked the keybag
 227                                  query_success = true;   // NOT unlock_success because we have the wrong lock
 228                              }
 229                          }   // StSyncLock goes out of scope, we have common lock again
 230                          bool locked = false;
 231                          service_context_t context = db.common().session().get_current_service_context();
 232                          if ((service_client_kb_is_locked(&context, &locked, NULL) == 0) && !locked) {
 233                              unlock_success = true;
 234                          }
 235                          if (looped) {
 236                              secnotice("KCdb", "Unlocking the keybag again (threading?)");
 237                          }
 238                          looped = true;
 239                      } while (query_success && !unlock_success);
 240                  }
 241                  break;
 242                  // try to use an explicitly given passphrase - Data:passphrase
 243                  case CSSM_SAMPLE_TYPE_PASSWORD: {
 244                      if (sample.length() != 2)
 245                          CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE);
 246                      secinfo("KCdb", "attempting passphrase unlock of keybag");
 247                      if (unlock_keybag(db, sample[1].data().data(), (int)sample[1].data().length())) {
 248                          return true;
 249                      }
 250                      break;
 251                  }
 252                  default: {
 253                      // Unknown sub-sample for unlocking.
 254                      secinfo("KCdb", "keybag: unknown sub-sample unlock (%d) ignored", sample.type());
 255                      break;
 256                  }
 257              }
 258          }
 259      }
 260      return false;
 261  }
 262  
 263  //
 264  // Create a Database object from initial parameters (create operation)
 265  //
 266  KeychainDatabase::KeychainDatabase(const DLDbIdentifier &id, const DBParameters &params, Process &proc,
 267              const AccessCredentials *cred, const AclEntryPrototype *owner)
 268      : LocalDatabase(proc), mValidData(false), mSecret(Allocator::standard(Allocator::sensitive)), mSaveSecret(false), version(0), mBlob(NULL), mRecoded(false)
 269  {
 270      // save a copy of the credentials for later access control
 271      mCred = DataWalkers::copy(cred, Allocator::standard());
 272  
 273      // create a new random signature to complete the DLDbIdentifier
 274      DbBlob::Signature newSig;
 275      
 276      (MacOSError::check)(SecRandomCopyBytes(kSecRandomDefault, sizeof(newSig.bytes), newSig.bytes));
 277      DbIdentifier ident(id, newSig);
 278  	
 279      // create common block and initialize
 280      // Since this is a creation step, figure out the correct blob version for this database
 281      RefPointer<KeychainDbCommon> newCommon = new KeychainDbCommon(proc.session(), ident, CommonBlob::getCurrentVersionForDb(ident.dbName()));
 282      newCommon->initializeKeybag();
 283  
 284  	StLock<Mutex> _(*newCommon);
 285  	parent(*newCommon);
 286  	newCommon->insert();
 287  	// new common is now visible (in ident-map) but we hold its lock
 288  
 289  	// establish the new master secret
 290  	establishNewSecrets(cred, SecurityAgent::newDatabase, false);
 291  	
 292  	// set initial database parameters
 293  	common().mParams = params;
 294  		
 295  	// the common is "unlocked" now
 296  	common().makeNewSecrets();
 297  
 298  	// establish initial ACL
 299  	if (owner)
 300  		acl().cssmSetInitial(*owner);
 301  	else
 302  		acl().cssmSetInitial(new AnyAclSubject());
 303      mValidData = true;
 304      
 305      // for now, create the blob immediately
 306      encode();
 307      
 308  	proc.addReference(*this);
 309  	
 310  	// this new keychain is unlocked; make it so
 311  	activity();
 312  	
 313      secinfo("KCdb", "creating keychain %p %s with common %p", this, (char*)this->dbName(), &common());
 314  }
 315  
 316  
 317  //
 318  // Create a Database object from a database blob (decoding)
 319  //
 320  KeychainDatabase::KeychainDatabase(const DLDbIdentifier &id, const DbBlob *blob, Process &proc,
 321      const AccessCredentials *cred)
 322  	: LocalDatabase(proc), mValidData(false), mSecret(Allocator::standard(Allocator::sensitive)), mSaveSecret(false), version(0), mBlob(NULL), mRecoded(false)
 323  {
 324  	validateBlob(blob);
 325  
 326      // save a copy of the credentials for later access control
 327      mCred = DataWalkers::copy(cred, Allocator::standard());
 328      mBlob = blob->copy();
 329      
 330      // check to see if we already know about this database
 331      DbIdentifier ident(id, blob->randomSignature);
 332  	Session &session = process().session();
 333  	RefPointer<KeychainDbCommon> com;
 334      secinfo("kccommon", "looking for a common at %s", ident.dbName());
 335  	if (KeychainDbCommon::find(ident, session, com)) {
 336  		parent(*com);
 337          secinfo("KCdb", "joining keychain %p %s with common %p", this, (char*)this->dbName(), &common());
 338  	} else {
 339  		// DbCommon not present; make a new one
 340          secinfo("kccommon", "no common found");
 341  		parent(*com);
 342  		common().mParams = blob->params;
 343          secinfo("KCdb", "making keychain %p %s with common %p", this, (char*)this->dbName(), &common());
 344  		// this DbCommon is locked; no timer or reference setting
 345  	}
 346  	proc.addReference(*this);
 347  }
 348  
 349  void KeychainDbCommon::insert()
 350  {
 351      StReadWriteLock _(mRWCommonLock, StReadWriteLock::Write);
 352      insertHoldingLock();
 353  }
 354  
 355  void KeychainDbCommon::insertHoldingLock()
 356  {
 357      mCommonSet.insert(this);
 358  }
 359  
 360  
 361  
 362  // find or make a DbCommon. Returns true if an existing one was found and used.
 363  bool KeychainDbCommon::find(const DbIdentifier &ident, Session &session, RefPointer<KeychainDbCommon> &common, uint32 requestedVersion, KeychainDbCommon* cloneFrom)
 364  {
 365      // Prepare to drop the mRWCommonLock.
 366      {
 367          StReadWriteLock _(mRWCommonLock, StReadWriteLock::Read);
 368          for (CommonSet::const_iterator it = mCommonSet.begin(); it != mCommonSet.end(); ++it) {
 369              if (&session == &(*it)->session() && ident == (*it)->identifier()) {
 370                  common = *it;
 371                  secinfo("kccommon", "found a common for %s at %p", ident.dbName(), common.get());
 372                  return true;
 373              }
 374          }
 375      }
 376  
 377      // not found. Grab the write lock, ensure that nobody has beaten us to adding,
 378      // and then create a DbCommon and add it to the map.
 379      {
 380          StReadWriteLock _(mRWCommonLock, StReadWriteLock::Write);
 381          for (CommonSet::const_iterator it = mCommonSet.begin(); it != mCommonSet.end(); ++it) {
 382              if (&session == &(*it)->session() && ident == (*it)->identifier()) {
 383                  common = *it;
 384                  secinfo("kccommon", "found a common for %s at %p", ident.dbName(), common.get());
 385                  return true;
 386              }
 387          }
 388  
 389          // not found
 390          if(cloneFrom) {
 391              common = new KeychainDbCommon(session, ident, *cloneFrom);
 392          } else if(requestedVersion != CommonBlob::version_none) {
 393              common = new KeychainDbCommon(session, ident, requestedVersion);
 394          } else {
 395              common = new KeychainDbCommon(session, ident);
 396          }
 397  
 398          secinfo("kccommon", "made a new common for %s at %p", ident.dbName(), common.get());
 399  
 400          // Can't call insert() here, because it grabs the write lock (which we have).
 401          common->insertHoldingLock();
 402      }
 403      common->initializeKeybag();
 404      return false;
 405  }
 406  
 407  // recode/clone:
 408  //
 409  // Special-purpose constructor for keychain synchronization.  Copies an
 410  // existing keychain but uses the operational keys from secretsBlob.  The 
 411  // new KeychainDatabase will silently replace the existing KeychainDatabase
 412  // as soon as the client declares that re-encoding of all keychain items is
 413  // finished.  This is a little perilous since it allows a client to dictate
 414  // securityd state, but we try to ensure that only the client that started 
 415  // the re-encoding can declare it done.  
 416  //
 417  KeychainDatabase::KeychainDatabase(KeychainDatabase &src, Process &proc, DbHandle dbToClone)
 418  	: LocalDatabase(proc), mValidData(false), mSecret(Allocator::standard(Allocator::sensitive)), mSaveSecret(false), version(0), mBlob(NULL), mRecoded(false)
 419  {
 420  	mCred = DataWalkers::copy(src.mCred, Allocator::standard());
 421  
 422  	// Give this KeychainDatabase a temporary name
 423  	std::string newDbName = std::string("////") + std::string(src.identifier().dbName());
 424  	DLDbIdentifier newDLDbIdent(src.identifier().dlDbIdentifier().ssuid(), newDbName.c_str(), src.identifier().dlDbIdentifier().dbLocation());
 425  	DbIdentifier ident(newDLDbIdent, src.identifier());
 426  
 427      // create common block and initialize
 428  	RefPointer<KeychainDbCommon> newCommon = new KeychainDbCommon(proc.session(), ident);
 429      newCommon->initializeKeybag();
 430  	StLock<Mutex> _(*newCommon);
 431  	parent(*newCommon);
 432  	newCommon->insert();
 433  
 434  	// set initial database parameters from the source keychain
 435  	common().mParams = src.common().mParams;
 436  	
 437  	// establish the source keychain's master secret as ours
 438  	// @@@  NB: this is a v. 0.1 assumption.  We *should* trigger new UI 
 439  	//      that offers the user the option of using the existing password 
 440  	//      or choosing a new one.  That would require a new 
 441  	//      SecurityAgentQuery type, new UI, and--possibly--modifications to
 442  	//      ensure that the new password is available here to generate the 
 443  	//      new master secret.  
 444  	src.unlockDb(false);		// precaution for masterKey()
 445  	common().setup(src.blob(), src.common().masterKey());
 446  	
 447      // import the operational secrets
 448  	RefPointer<KeychainDatabase> srcKC = Server::keychain(dbToClone);
 449  	common().importSecrets(srcKC->common());
 450  	
 451  	// import source keychain's ACL  
 452  	CssmData pubAcl, privAcl;
 453  	src.acl().exportBlob(pubAcl, privAcl);
 454  	importBlob(pubAcl.data(), privAcl.data());
 455  	src.acl().allocator.free(pubAcl);
 456  	src.acl().allocator.free(privAcl);
 457  	
 458  	// indicate that this keychain should be allowed to do some otherwise
 459  	// risky things required for copying, like re-encoding keys
 460  	mRecodingSource = &src;
 461  	
 462  	common().setUnlocked();
 463  	mValidData = true;
 464  	
 465      encode();
 466  
 467  	proc.addReference(*this);
 468  	secinfo("SSdb", "database %s(%p) created as copy, common at %p",
 469  			 common().dbName(), this, &common());
 470  }
 471  
 472  // Make a new KeychainDatabase from an old one, but have a completely different location
 473  KeychainDatabase::KeychainDatabase(const DLDbIdentifier& id, KeychainDatabase &src, Process &proc)
 474  : LocalDatabase(proc), mValidData(false), mSecret(Allocator::standard(Allocator::sensitive)), mSaveSecret(false), version(0), mBlob(NULL), mRecoded(false)
 475  {
 476      mCred = DataWalkers::copy(src.mCred, Allocator::standard());
 477  
 478      DbIdentifier ident(id, src.identifier());
 479  
 480      // create common block and initialize
 481      RefPointer<KeychainDbCommon> newCommon;
 482      if(KeychainDbCommon::find(ident, process().session(), newCommon, CommonBlob::version_none, &src.common())) {
 483          // A common already existed. Write over it, but note that everything may go horribly from here on out.
 484          secinfo("kccommon", "Found common where we didn't expect. Possible strange behavior ahead.");
 485          newCommon->cloneFrom(src.common());
 486      }
 487  
 488      StLock<Mutex> _(*newCommon);
 489      parent(*newCommon);
 490  
 491      // set initial database parameters from the source keychain
 492      common().mParams = src.common().mParams;
 493  
 494      // import source keychain's ACL
 495      CssmData pubAcl, privAcl;
 496      src.acl().exportBlob(pubAcl, privAcl);
 497      importBlob(pubAcl.data(), privAcl.data());
 498      src.acl().allocator.free(pubAcl);
 499      src.acl().allocator.free(privAcl);
 500  
 501      // Copy the source database's blob, if possible
 502      if(src.mBlob) {
 503          mBlob = src.mBlob->copy();
 504          version = src.version;
 505      }
 506  
 507      // We've copied everything we can from our source. If they were valid, so are we.
 508      mValidData = src.mValidData;
 509  
 510      proc.addReference(*this);
 511      secinfo("SSdb", "database %s(%p) created as expected clone, common at %p", common().dbName(), this, &common());
 512  }
 513  
 514  
 515  // Make a new KeychainDatabase from an old one, but have entirely new operational secrets
 516  KeychainDatabase::KeychainDatabase(uint32 requestedVersion, KeychainDatabase &src, Process &proc)
 517  : LocalDatabase(proc), mValidData(false), mSecret(Allocator::standard(Allocator::sensitive)), mSaveSecret(false), version(0), mBlob(NULL), mRecoded(false)
 518  {
 519      mCred = DataWalkers::copy(src.mCred, Allocator::standard());
 520  
 521      // Give this KeychainDatabase a temporary name
 522      // this must canonicalize to a different path than the original DB, otherwise another process opening the existing DB wil find this new KeychainDbCommon
 523      // and call decodeCore with the old blob, overwriting the new secrets and wreaking havoc
 524      std::string newDbName = std::string("////") + std::string(src.identifier().dbName()) + std::string("_com.apple.security.keychain.migrating");
 525      DLDbIdentifier newDLDbIdent(src.identifier().dlDbIdentifier().ssuid(), newDbName.c_str(), src.identifier().dlDbIdentifier().dbLocation());
 526      DbIdentifier ident(newDLDbIdent, src.identifier());
 527  
 528      // hold the lock for src's common during this operation (to match locking common locking order with KeychainDatabase::recodeKey)
 529      StLock<Mutex> __(src.common());
 530  
 531      // create common block and initialize
 532      RefPointer<KeychainDbCommon> newCommon;
 533      if(KeychainDbCommon::find(ident, process().session(), newCommon, requestedVersion)) {
 534          // A common already existed here. Write over it, but note that everything may go horribly from here on out.
 535          secinfo("kccommon", "Found common where we didn't expect. Possible strange behavior ahead.");
 536          newCommon->cloneFrom(src.common(), requestedVersion);
 537      }
 538      newCommon->initializeKeybag();
 539      StLock<Mutex> _(*newCommon);
 540      parent(*newCommon);
 541  
 542      // We want to re-use the master secrets from the source database (and so the
 543      // same password), but reroll new operational secrets.
 544  
 545      // Copy the master secret over...
 546      src.unlockDb(false); // precaution
 547  
 548      common().setup(src.blob(), src.common().masterKey(), false); // keep the new common's version intact
 549  
 550      // set initial database parameters from the source keychain
 551      common().mParams = src.common().mParams;
 552  
 553      // and make new operational secrets
 554      common().makeNewSecrets();
 555  
 556      // import source keychain's ACL
 557      CssmData pubAcl, privAcl;
 558      src.acl().exportBlob(pubAcl, privAcl);
 559      importBlob(pubAcl.data(), privAcl.data());
 560      src.acl().allocator.free(pubAcl);
 561      src.acl().allocator.free(privAcl);
 562  
 563      // indicate that this keychain should be allowed to do some otherwise
 564      // risky things required for copying, like re-encoding keys
 565      mRecodingSource = &src;
 566  
 567      common().setUnlocked();
 568      mValidData = true;
 569  
 570      encode();
 571  
 572      proc.addReference(*this);
 573      secinfo("SSdb", "database %s(%p) created as expected copy, common at %p",
 574               common().dbName(), this, &common());
 575  }
 576  
 577  //
 578  // Destroy a Database
 579  //
 580  KeychainDatabase::~KeychainDatabase()
 581  {
 582      secinfo("KCdb", "deleting database %s(%p) common %p",
 583          common().dbName(), this, &common());
 584      Allocator::standard().free(mCred);
 585  	Allocator::standard().free(mBlob);
 586  }
 587  
 588  
 589  //
 590  // Basic Database virtual implementations
 591  //
 592  KeychainDbCommon &KeychainDatabase::common() const
 593  {
 594  	return parent<KeychainDbCommon>();
 595  }
 596  
 597  const char *KeychainDatabase::dbName() const
 598  {
 599  	return common().dbName();
 600  }
 601  
 602  bool KeychainDatabase::transient() const
 603  {
 604  	return false;	// has permanent store
 605  }
 606  
 607  AclKind KeychainDatabase::aclKind() const
 608  {
 609  	return dbAcl;
 610  }
 611  
 612  Database *KeychainDatabase::relatedDatabase()
 613  {
 614  	return this;
 615  }
 616  
 617  //
 618  // (Re-)Authenticate the database. This changes the stored credentials.
 619  //
 620  void KeychainDatabase::authenticate(CSSM_DB_ACCESS_TYPE mode,
 621  	const AccessCredentials *cred)
 622  {
 623  	StLock<Mutex> _(common());
 624  	
 625  	// the (Apple specific) RESET bit means "lock the database now"
 626  	switch (mode) {
 627  	case CSSM_DB_ACCESS_RESET:
 628  		secinfo("KCdb", "%p ACCESS_RESET triggers keychain lock", this);
 629  		common().lockDb();
 630  		break;
 631  	default:
 632  		//  store the new credentials for future use
 633  		secinfo("KCdb", "%p authenticate stores new database credentials", this);
 634  		AccessCredentials *newCred = DataWalkers::copy(cred, Allocator::standard());
 635  		Allocator::standard().free(mCred);
 636  		mCred = newCred;
 637  	}
 638  }
 639  
 640  
 641  //
 642  // Make a new KeychainKey.
 643  // If PERMANENT is off, make a temporary key instead.
 644  // The db argument allows you to create for another KeychainDatabase (only);
 645  // it defaults to ourselves.
 646  //
 647  RefPointer<Key> KeychainDatabase::makeKey(Database &db, const CssmKey &newKey,
 648  	uint32 moreAttributes, const AclEntryPrototype *owner)
 649  {
 650      StLock<Mutex> lock(common());
 651  	if (moreAttributes & CSSM_KEYATTR_PERMANENT)
 652  		return new KeychainKey(db, newKey, moreAttributes, owner);
 653  	else
 654  		return process().makeTemporaryKey(newKey, moreAttributes, owner);
 655  }
 656  
 657  RefPointer<Key> KeychainDatabase::makeKey(const CssmKey &newKey,
 658  	uint32 moreAttributes, const AclEntryPrototype *owner)
 659  {
 660  	return makeKey(*this, newKey, moreAttributes, owner);
 661  }
 662  
 663  
 664  //
 665  // Return the database blob, recalculating it as needed.
 666  //
 667  DbBlob *KeychainDatabase::blob()
 668  {
 669  	StLock<Mutex> _(common());
 670      if (!validBlob()) {
 671          makeUnlocked(false);	// unlock to get master secret
 672  		encode();				// (re)encode blob if needed
 673      }
 674      activity();					// reset timeout
 675  	assert(validBlob());		// better have a valid blob now...
 676      return mBlob;
 677  }
 678  
 679  
 680  //
 681  // Encode the current database as a blob.
 682  // Note that this returns memory we own and keep.
 683  // Caller must hold common lock.
 684  //
 685  void KeychainDatabase::encode()
 686  {
 687  	DbBlob *blob = common().encode(*this);
 688  	Allocator::standard().free(mBlob);
 689  	mBlob = blob;
 690  	version = common().version;
 691  	secinfo("KCdb", "encoded database %p common %p(%s) version %u params=(%u,%u)",
 692  		this, &common(), dbName(), version,
 693  		common().mParams.idleTimeout, common().mParams.lockOnSleep);
 694  }
 695  
 696  //
 697  // Change the passphrase on a database
 698  //
 699  void KeychainDatabase::changePassphrase(const AccessCredentials *cred)
 700  {
 701  	// get and hold the common lock (don't let other threads break in here)
 702  	StLock<Mutex> _(common());
 703  
 704      list<CssmSample> samples;
 705      bool hasOldSecret = cred && cred->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK, samples);
 706      samples.clear();    // Can't count the samples at the end because I could specify CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK twice
 707      bool hasNewSecret = cred && cred->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK, samples);
 708  
 709      // If no creds we do interactive, if both we do silently. If unequal, think harder.
 710      if (hasOldSecret != hasNewSecret) {
 711          if (!hasOldSecret && !isLocked()) {
 712              // Alternative: do a confirm_access SA dialog and run validatePassphrase on it (what client name?)
 713              // That's risky for now, but it would cover the remaining use case.
 714              secerror("KCdb: changePassphrase credential set has no old secret and KC not locked");
 715              MacOSError::throwMe(errSecAuthFailed);
 716          }
 717      }
 718  
 719      secnotice("KCdb", "changePassphrase proceeding with old %i, new %i, locked %i", hasOldSecret, hasNewSecret, isLocked());
 720  
 721      if (hasOldSecret && !checkCredentials(cred)) {
 722          secinfo("KCdb", "Cannot change passphrase for (%s): existing passphrase does not match", common().dbName());
 723          MacOSError::throwMe(errSecAuthFailed);
 724      }
 725  
 726  	// establish OLD secret - i.e. unlock the database. You'll be prompted if !hasOldSecrets and DB is locked.
 727      if (common().isLoginKeychain()) mSaveSecret = true;
 728  	makeUnlocked(cred, false);
 729  	
 730      // establish NEW secret
 731      if(!establishNewSecrets(cred, SecurityAgent::changePassphrase, true)) {
 732          secinfo("KCdb", "Old and new passphrases are the same. Database %s(%p) master secret did not change.",
 733                   common().dbName(), this);
 734          return;
 735      }
 736      if (mSecret) { mSecret.reset(); }
 737      mSaveSecret = false;
 738  	common().invalidateBlob();	// blob state changed
 739  	secinfo("KCdb", "Database %s(%p) master secret changed", common().dbName(), this);
 740  	encode();			// force rebuild of local blob
 741  	
 742  	// send out a notification
 743  	notify(kNotificationEventPassphraseChanged);
 744  
 745      // I guess this counts as an activity
 746      activity();
 747  }
 748  
 749  //
 750  // Second stage of keychain synchronization: overwrite the original keychain's
 751  // (this KeychainDatabase's) operational secrets
 752  //
 753  void KeychainDatabase::commitSecretsForSync(KeychainDatabase &cloneDb)
 754  {
 755      StLock<Mutex> _(common());
 756      
 757  	// try to detect spoofing
 758  	if (cloneDb.mRecodingSource != this) 
 759          CssmError::throwMe(CSSM_ERRCODE_INVALID_DB_HANDLE);
 760  	
 761      // in case we autolocked since starting the sync
 762      makeUnlocked(false); // call this because we already own the lock
 763  	cloneDb.unlockDb(false); // we may not own the lock here, so calling unlockDb will lock the cloneDb's common lock
 764  
 765      // Decode all keys whose handles refer to this on-disk keychain so that
 766      // if the holding client commits the key back to disk, it's encoded with
 767      // the new operational secrets.  The recoding client *must* hold a write
 768      // lock for the on-disk keychain from the moment it starts recoding key
 769      // items until after this call.  
 770      // 
 771  	// @@@  This specific implementation is a workaround for 4003540.  
 772  	std::vector<U32HandleObject::Handle> handleList;
 773  	U32HandleObject::findAllRefs<KeychainKey>(handleList);
 774      size_t count = handleList.size();
 775  	if (count > 0) {
 776          for (unsigned int n = 0; n < count; ++n) {
 777              RefPointer<KeychainKey> kckey = 
 778                  U32HandleObject::findRefAndLock<KeychainKey>(handleList[n], CSSMERR_CSP_INVALID_KEY_REFERENCE);
 779              StLock<Mutex> _(*kckey/*, true*/);
 780              if (kckey->database().global().identifier() == identifier()) {
 781                  kckey->key();               // force decode
 782                  kckey->invalidateBlob();
 783  				secinfo("kcrecode", "changed extant key %p (proc %d)",
 784  						 &*kckey, kckey->process().pid());
 785              }
 786          }
 787  	}
 788  
 789      // mark down that we just recoded
 790      mRecoded = true;
 791  
 792      // it is now safe to replace the old op secrets
 793      common().importSecrets(cloneDb.common());
 794  	common().invalidateBlob();
 795  }
 796  
 797  
 798  //
 799  // Extract the database master key as a proper Key object.
 800  //
 801  RefPointer<Key> KeychainDatabase::extractMasterKey(Database &db,
 802  	const AccessCredentials *cred, const AclEntryPrototype *owner,
 803  	uint32 usage, uint32 attrs)
 804  {
 805  	// get and hold common lock
 806  	StLock<Mutex> _(common());
 807  	
 808  	// force lock to require re-validation of credentials
 809  	lockDb();
 810  	
 811  	// unlock to establish master secret
 812  	makeUnlocked(false);
 813  	
 814  	// extract the raw cryptographic key
 815  	CssmClient::WrapKey wrap(Server::csp(), CSSM_ALGID_NONE);
 816  	CssmKey key;
 817  	wrap(common().masterKey(), key);
 818  	
 819  	// make the key object and return it
 820  	return makeKey(db, key, attrs & LocalKey::managedAttributes, owner);
 821  }
 822  
 823  
 824  //
 825  // Unlock this database (if needed) by obtaining the master secret in some
 826  // suitable way and then proceeding to unlock with it.
 827  // Does absolutely nothing if the database is already unlocked.
 828  // The makeUnlocked forms are identical except the assume the caller already
 829  // holds the common lock.
 830  //
 831  void KeychainDatabase::unlockDb(bool unlockKeybag)
 832  {
 833  	StLock<Mutex> _(common());
 834  	makeUnlocked(unlockKeybag);
 835  }
 836  
 837  void KeychainDatabase::makeUnlocked(bool unlockKeybag)
 838  {
 839  	return makeUnlocked(mCred, unlockKeybag);
 840  }
 841  
 842  void KeychainDatabase::makeUnlocked(const AccessCredentials *cred, bool unlockKeybag)
 843  {
 844      if (isLocked()) {
 845  		secnotice("KCdb", "%p(%p) unlocking for makeUnlocked()", this, &common());
 846          assert(mBlob || (mValidData && common().hasMaster()));
 847          bool asking_again = false;
 848          do {
 849              if (asking_again) {
 850                  secnotice("KCdb", "makeUnlocked: establishing old secrets again (threading?)");
 851              }
 852              establishOldSecrets(cred);
 853              asking_again = true;
 854          } while (!common().hasMaster());
 855  		common().setUnlocked(); // mark unlocked
 856          if (common().isLoginKeychain()) {
 857              CssmKey master = common().masterKey();
 858              CssmKey rawMaster;
 859              CssmClient::WrapKey wrap(Server::csp(), CSSM_ALGID_NONE);
 860              wrap(master, rawMaster);
 861              
 862              service_context_t context = common().session().get_current_service_context();
 863              service_client_stash_load_key(&context, rawMaster.keyData(), (int)rawMaster.length());
 864          }
 865  	} else if (unlockKeybag && common().isLoginKeychain()) {
 866          bool locked = false;
 867          service_context_t context = common().session().get_current_service_context();
 868          if ((service_client_kb_is_locked(&context, &locked, NULL) == 0) && locked) {
 869              if (!unlock_keybag_with_cred(*this, cred)) {
 870                  syslog(LOG_NOTICE, "failed to unlock iCloud keychain");
 871              }
 872          }
 873      }
 874  	if (!mValidData) {	// need to decode to get our ACLs, master secret available
 875  		secnotice("KCdb", "%p(%p) is unlocked; decoding for makeUnlocked()", this, &common());
 876  		if (!decode())
 877  			CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
 878  	}
 879  	assert(!isLocked());
 880  	assert(mValidData);
 881  }
 882  
 883  /**
 884   Invoke securityd_service to load the keybag and retrieve the masterkey.
 885   Also load masterkey from KeychainStasher and compare to make sure new stash works properly
 886   */
 887  void KeychainDatabase::stashDbCheck()
 888  {
 889      secnotice("KCdb", "Loading stashed key");
 890      CssmAutoData masterKey(Allocator::standard(Allocator::sensitive));
 891      CssmAutoData encKey(Allocator::standard(Allocator::sensitive));
 892  
 893      // We're going to double-load during transition
 894      void* s_key = NULL;
 895      size_t s_keylen = 0;
 896      service_context_t context = common().session().get_current_service_context();
 897      // SIDE EFFECT: loads the user's keybag
 898      int servicerc = service_client_stash_get_key(&context, &s_key, &s_keylen);
 899      if (servicerc != KB_Success) {
 900          secerror("KCdb: failed to load stash from securityd_service: %d", servicerc);
 901      } else {
 902          secnotice("KCdb", "securityd_service claims get_key success");
 903      }
 904  
 905      void* a_key = NULL;
 906      size_t a_keylen = 0;
 907      OSStatus agentrc = loadKeyFromStashAgent(common().session().originatorUid(), &a_key, &a_keylen);
 908      if (agentrc != errSecSuccess) {
 909          secerror("KCdb: failed to load stash from KeychainStasher: %d", (int)agentrc);
 910      } else {
 911          secnotice("KCdb", "KeychainStasher claims loadKey success");
 912      }
 913  
 914      void* key = NULL;
 915      size_t keylen = 0;
 916      if (servicerc != KB_Success && agentrc != errSecSuccess) {
 917          __security_simulatecrash(CFSTR("Both old and new stashes failed to load"), __sec_exception_code_BadStash);
 918          CssmError::throwMe(servicerc);  // For now
 919      } else if (servicerc == KB_Success && agentrc == errSecSuccess) {
 920          if (s_keylen != a_keylen || a_keylen == 0) {
 921              __security_simulatecrash(CFSTR("Stashed key lengths disagree or are zero"), __sec_exception_code_BadStash);
 922          } else if (cc_cmp_safe(a_keylen, a_key, s_key) != 0) {
 923              __security_simulatecrash(CFSTR("Keybytes disagree"), __sec_exception_code_BadStash);
 924          }
 925  
 926          key = a_key;
 927          keylen = a_keylen;
 928          memset_s(s_key, s_keylen, 0, s_keylen);
 929          free(s_key);
 930      } else if (servicerc == KB_Success) {
 931          key = s_key;
 932          keylen = s_keylen;
 933      } else if (agentrc == errSecSuccess) {
 934          key = a_key;
 935          keylen = a_keylen;
 936      }
 937  
 938      masterKey.copy(CssmData(key, keylen));
 939      memset_s(key, keylen, 0, keylen);
 940      free(key);
 941  
 942      secnotice("KCdb", "Retrieved stashed key, will establish");
 943      {
 944          StLock<Mutex> _(common());
 945  
 946          // Now establish it as the keychain master key
 947          CssmClient::Key key(Server::csp(), masterKey.get());
 948          CssmKey::Header &hdr = key.header();
 949          hdr.keyClass(CSSM_KEYCLASS_SESSION_KEY);
 950          hdr.algorithm(CSSM_ALGID_3DES_3KEY_EDE);
 951          hdr.usage(CSSM_KEYUSE_ANY);
 952          hdr.blobType(CSSM_KEYBLOB_RAW);
 953          hdr.blobFormat(CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING);
 954          common().setup(mBlob, key);
 955  
 956          if (!decode()) {
 957              CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
 958          }
 959  
 960          common().get_encryption_key(encKey);
 961      }
 962  
 963      // when upgrading from pre-10.9 create a keybag if it doesn't exist with the encryption key
 964      // only do this after we have verified the master key unlocks the login.keychain
 965      if (service_client_kb_load(&context) == KB_BagNotFound) {
 966          service_client_kb_create(&context, encKey.data(), (int)encKey.length());
 967      }
 968  }
 969  
 970  //
 971  // Get the keychain master key and invoke the securityd_service
 972  // to stash it in the AppleFDEKeyStore ready for commit to the
 973  // NVRAM blob.
 974  //
 975  void KeychainDatabase::stashDb()
 976  {
 977      secnotice("KCdb", "Let's stash a key");
 978      CssmAutoData data(Allocator::standard(Allocator::sensitive));
 979      
 980      {
 981          StLock<Mutex> _(common());
 982          if (!common().isValid()) {
 983              CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
 984          }
 985          
 986          CssmKey key = common().masterKey();
 987          data.copy(key.keyData());
 988      }
 989  
 990      // We're going to double-stash during transition
 991      service_context_t context = common().session().get_current_service_context();
 992      int servicerc = service_client_stash_set_key(&context, data.data(), (int)data.length());
 993      if (servicerc != KB_Success) {
 994          secerror("KCdb: securityd_service stash failed: %d", servicerc);
 995      } else {
 996          secnotice("KCdb", "securityd_service claims successful stash");
 997      }
 998  
 999      OSStatus agentrc = stashKeyWithStashAgent(common().session().originatorUid(), data.data(), data.length());
1000      if (agentrc != errSecSuccess) {
1001          secerror("KCdb: KeychainStasher stash failed: %d", (int)agentrc);
1002      } else {
1003          secnotice("KCdb", "KeychainStasher claims successful stash");
1004      }
1005  
1006      if (servicerc != KB_Success && agentrc != errSecSuccess) {
1007          __security_simulatecrash(CFSTR("Both old and new stash mechanisms failed"), __sec_exception_code_BadStash);
1008          CssmError::throwMe(servicerc);  // For now
1009      }
1010      secnotice("KCdb", "Key stashed");
1011  }
1012  
1013  //
1014  // The following unlock given an explicit passphrase, rather than using
1015  // (special cred sample based) default procedures.
1016  //
1017  void KeychainDatabase::unlockDb(const CssmData &passphrase, bool unlockKeybag)
1018  {
1019  	StLock<Mutex> _(common());
1020  	makeUnlocked(passphrase, unlockKeybag);
1021  }
1022  
1023  void KeychainDatabase::makeUnlocked(const CssmData &passphrase, bool unlockKeybag)
1024  {
1025  	if (isLocked()) {
1026  		if (decode(passphrase))
1027  			return;
1028  		else
1029  			CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
1030  	} else if (!mValidData)	{	// need to decode to get our ACLs, passphrase available
1031  		if (!decode())
1032  			CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
1033  	}
1034  
1035      if (unlockKeybag && common().isLoginKeychain()) {
1036          bool locked = false;
1037          service_context_t context = common().session().get_current_service_context();
1038          if (!common().session().keybagGetState(session_keybag_check_master_key) || ((service_client_kb_is_locked(&context, &locked, NULL) == 0) && locked)) {
1039              unlock_keybag(*this, passphrase.data(), (int)passphrase.length());
1040          }
1041      }
1042  
1043  	assert(!isLocked());
1044  	assert(mValidData);
1045  }
1046  
1047  
1048  //
1049  // Nonthrowing passphrase-based unlock. This returns false if unlock failed.
1050  // Note that this requires an explicitly given passphrase.
1051  // Caller must hold common lock.
1052  //
1053  bool KeychainDatabase::decode(const CssmData &passphrase)
1054  {
1055  	assert(mBlob);
1056  	common().setup(mBlob, passphrase);
1057  	bool success = decode();
1058      if (success && common().isLoginKeychain()) {
1059          unlock_keybag(*this, passphrase.data(), (int)passphrase.length());
1060      }
1061      return success;
1062  }
1063  
1064  
1065  //
1066  // Given the established master secret, decode the working keys and other
1067  // functional secrets for this database. Return false (do NOT throw) if
1068  // the decode fails. Call this in low(er) level code once you established
1069  // the master key.
1070  //
1071  bool KeychainDatabase::decode()
1072  {
1073  	assert(mBlob);
1074  	assert(common().hasMaster());
1075  	void *privateAclBlob;
1076  	if (common().unlockDb(mBlob, &privateAclBlob)) {
1077  		if (!mValidData) {
1078  			acl().importBlob(mBlob->publicAclBlob(), privateAclBlob);
1079  			mValidData = true;
1080  		}
1081  		Allocator::standard().free(privateAclBlob);
1082  		return true;
1083  	}
1084  	secinfo("KCdb", "%p decode failed", this);
1085  	return false;
1086  }
1087  
1088  
1089  //
1090  // Given an AccessCredentials for this database, wring out the existing primary
1091  // database secret by whatever means necessary.
1092  // On entry, caller must hold the database common lock. It will be held
1093  // throughout except when user interaction is required. User interaction 
1094  // requires relinquishing the database common lock and taking the UI lock. On
1095  // return from user interaction, the UI lock is relinquished and the database
1096  // common lock must be reacquired. At no time may the caller hold both locks.
1097  // On exit, the crypto core has its master secret. If things go wrong,
1098  // we will throw a suitable exception. Note that encountering any malformed
1099  // credential sample will throw, but this is not guaranteed -- don't assume
1100  // that NOT throwing means creds is entirely well-formed (it may just be good
1101  // enough to work THIS time).
1102  //
1103  // How this works:
1104  // Walk through the creds. Fish out those credentials (in order) that
1105  // are for unlock processing (they have no ACL subject correspondents),
1106  // and (try to) obey each in turn, until one produces a valid secret
1107  // or you run out. If no special samples are found at all, interpret that as
1108  // "use the system global default," which happens to be hard-coded right here.
1109  //
1110  void KeychainDatabase::establishOldSecrets(const AccessCredentials *creds)
1111  {
1112  	bool forSystem = this->belongsToSystem();	// this keychain belongs to the system security domain
1113  
1114  	// attempt system-keychain unlock
1115  	if (forSystem) {
1116  		SystemKeychainKey systemKeychain(kSystemUnlockFile);
1117  		if (systemKeychain.matches(mBlob->randomSignature)) {
1118  			secinfo("KCdb", "%p attempting system unlock", this);
1119  			common().setup(mBlob, CssmClient::Key(Server::csp(), systemKeychain.key(), true));
1120  			if (decode())
1121  				return;
1122  		}
1123  	}
1124      
1125  	list<CssmSample> samples;
1126  	if (creds && creds->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK, samples)) {
1127  		for (list<CssmSample>::iterator it = samples.begin(); it != samples.end(); it++) {
1128  			TypedList &sample = *it;
1129  			sample.checkProper();
1130  			switch (sample.type()) {
1131  			// interactively prompt the user - no additional data
1132  			case CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT:
1133  				if (!forSystem) {
1134  					if (interactiveUnlock())
1135  						return;
1136  				}
1137                  break;
1138  			// try to use an explicitly given passphrase - Data:passphrase
1139  			case CSSM_SAMPLE_TYPE_PASSWORD:
1140  				if (sample.length() != 2)
1141  					CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE);
1142  				secinfo("KCdb", "%p attempting passphrase unlock", this);
1143  				if (decode(sample[1]))
1144  					return;
1145  				break;
1146  			// try to open with a given master key - Data:CSP or KeyHandle, Data:CssmKey
1147  			case CSSM_SAMPLE_TYPE_SYMMETRIC_KEY:
1148  			case CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY:
1149  				assert(mBlob);
1150  				secinfo("KCdb", "%p attempting explicit key unlock", this);
1151  				common().setup(mBlob, keyFromCreds(sample, 4));
1152                  if (decode()) {
1153  					return;
1154                  }
1155  				break;
1156  			case CSSM_SAMPLE_TYPE_KEYBAG_KEY:
1157  				assert(mBlob);
1158  				secinfo("KCdb", "%p attempting keybag key unlock", this);
1159  				common().setup(mBlob, keyFromKeybag(sample));
1160  				if (decode()) {
1161  					return;
1162  				}
1163  				break;
1164  			// explicitly defeat the default action but don't try anything in particular
1165  			case CSSM_WORDID_CANCELED:
1166  				secinfo("KCdb", "%p defeat default action", this);
1167  				break;
1168  			default:
1169  				// Unknown sub-sample for unlocking.
1170  				// If we wanted to be fascist, we could now do
1171  				//  CssmError::throwMe(CSSM_ERRCODE_SAMPLE_VALUE_NOT_SUPPORTED);
1172  				// But instead we try to be tolerant and continue on.
1173  				// This DOES however count as an explicit attempt at specifying unlock,
1174  				// so we will no longer try the default case below...
1175  				secinfo("KCdb", "%p unknown sub-sample unlock (%d) ignored", this, sample.type());
1176  				break;
1177  			}
1178  		}
1179  	} else {
1180  		// default action
1181  		assert(mBlob);
1182  
1183  		if (!forSystem) {
1184  			if (interactiveUnlock())
1185  				return;
1186  		}
1187  	}
1188  	
1189  	// out of options - no secret obtained
1190  	CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
1191  }
1192  
1193  //
1194  // This function is almost identical to establishOldSecrets, but:
1195  //   1. It will never prompt the user; these credentials either work or they don't
1196  //   2. It will not change the secrets of this database
1197  //
1198  // TODO: These two functions should probably be refactored to something nicer.
1199  bool KeychainDatabase::checkCredentials(const AccessCredentials *creds) {
1200  
1201      list<CssmSample> samples;
1202      if (creds && creds->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK, samples)) {
1203          for (list<CssmSample>::iterator it = samples.begin(); it != samples.end(); it++) {
1204              TypedList &sample = *it;
1205              sample.checkProper();
1206              switch (sample.type()) {
1207                  // interactively prompt the user - no additional data
1208                  case CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT:
1209                      // do nothing, because this function will never prompt the user
1210                      secinfo("integrity", "%p ignoring keychain prompt", this);
1211                      break;
1212                  // try to use an explicitly given passphrase - Data:passphrase
1213                  case CSSM_SAMPLE_TYPE_PASSWORD:
1214                      if (sample.length() != 2)
1215                          CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE);
1216                      secinfo("integrity", "%p checking passphrase", this);
1217                      if(validatePassphrase(sample[1])) {
1218                          return true;
1219                      }
1220                      break;
1221                  // try to open with a given master key - Data:CSP or KeyHandle, Data:CssmKey
1222                  case CSSM_SAMPLE_TYPE_SYMMETRIC_KEY:
1223                  case CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY:
1224                      assert(mBlob);
1225                      secinfo("integrity", "%p attempting explicit key unlock", this);
1226                      try {
1227                          CssmClient::Key checkKey = keyFromCreds(sample, 4);
1228                          if(common().validateKey(checkKey)) {
1229                              return true;
1230                          }
1231                      } catch(...) {
1232                          // ignore all problems in keyFromCreds
1233                          secinfo("integrity", "%p caught error", this);
1234                      }
1235                      break;
1236              }
1237          }
1238      }
1239  
1240      // out of options - credentials don't match
1241      return false;
1242  }
1243  
1244  uint32_t KeychainDatabase::interactiveUnlockAttempts = 0;
1245  
1246  // 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!
1247  // Try to hold the UI lock for the smallest amount of time possible while having the common lock where needed.
1248  bool KeychainDatabase::interactiveUnlock()
1249  {
1250  	secinfo("KCdb", "%p attempting interactive unlock", this);
1251      interactiveUnlockAttempts++;
1252  
1253  	SecurityAgent::Reason reason = SecurityAgent::noReason;
1254      QueryUnlock query(*this);
1255  
1256  	if (isLocked()) {
1257  		query.inferHints(Server::process());
1258          StSyncLock<Mutex, Mutex> uisync(common().uiLock(), common());
1259          reason = query();
1260          uisync.unlock();
1261          if (mSaveSecret && reason == SecurityAgent::noReason) {
1262              query.retrievePassword(mSecret);
1263          }
1264          query.disconnect();
1265  	} else {
1266  		secinfo("KCdb", "%p was unlocked during uiLock delay", this);
1267  	}
1268  
1269      if (common().isLoginKeychain()) {
1270          bool locked = false;
1271          service_context_t context = common().session().get_current_service_context();
1272          if ((service_client_kb_is_locked(&context, &locked, NULL) == 0) && locked) {
1273              QueryKeybagNewPassphrase keybagQuery(common().session());
1274              keybagQuery.inferHints(Server::process());
1275              CssmAutoData pass(Allocator::standard(Allocator::sensitive));
1276              CssmAutoData oldPass(Allocator::standard(Allocator::sensitive));
1277              StSyncLock<Mutex, Mutex> uisync(common().uiLock(), common());
1278              SecurityAgent::Reason queryReason = keybagQuery.query(oldPass, pass);
1279              uisync.unlock();
1280              if (queryReason == SecurityAgent::noReason) {
1281                  service_client_kb_change_secret(&context, oldPass.data(), (int)oldPass.length(), pass.data(), (int)pass.length());
1282              } else if (queryReason == SecurityAgent::resettingPassword) {
1283                  query.retrievePassword(pass);
1284                  service_client_kb_reset(&context, pass.data(), (int)pass.length());
1285              }
1286  
1287          }
1288      }
1289  
1290      return reason == SecurityAgent::noReason;
1291  }
1292  
1293  uint32_t KeychainDatabase::getInteractiveUnlockAttempts() {
1294      if (csr_check(CSR_ALLOW_APPLE_INTERNAL)) {
1295          // Not an internal install; don't answer
1296          return 0;
1297      } else {
1298          return interactiveUnlockAttempts;
1299      }
1300  }
1301  
1302  
1303  //
1304  // Same thing, but obtain a new secret somehow and set it into the common.
1305  //
1306  bool KeychainDatabase::establishNewSecrets(const AccessCredentials *creds, SecurityAgent::Reason reason, bool change)
1307  {
1308  	list<CssmSample> samples;
1309  	if (creds && creds->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK, samples)) {
1310  		for (list<CssmSample>::iterator it = samples.begin(); it != samples.end(); it++) {
1311  			TypedList &sample = *it;
1312  			sample.checkProper();
1313  			switch (sample.type()) {
1314  			// interactively prompt the user
1315  			case CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT:
1316                  {
1317                      secinfo("KCdb", "%p specified interactive passphrase", this);
1318                      QueryNewPassphrase query(*this, reason);
1319                      StSyncLock<Mutex, Mutex> uisync(common().uiLock(), common());
1320                      query.inferHints(Server::process());
1321                      CssmAutoData passphrase(Allocator::standard(Allocator::sensitive));
1322                      CssmAutoData oldPassphrase(Allocator::standard(Allocator::sensitive));
1323                      SecurityAgent::Reason reason(query(oldPassphrase, passphrase));
1324                      uisync.unlock();
1325                      if (reason == SecurityAgent::noReason) {
1326                          common().setup(NULL, passphrase);
1327                          change_secret_on_keybag(*this, oldPassphrase.data(), (int)oldPassphrase.length(), passphrase.data(), (int)passphrase.length());
1328                          return true;
1329                      }
1330                  }
1331  				break;
1332  			// try to use an explicitly given passphrase
1333  			case CSSM_SAMPLE_TYPE_PASSWORD:
1334  				{
1335                      secinfo("KCdb", "%p specified explicit passphrase", this);
1336                      if (sample.length() != 2)
1337                          CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE);
1338                      if (common().isLoginKeychain()) {
1339                          CssmAutoData oldPassphrase(Allocator::standard(Allocator::sensitive));
1340                          list<CssmSample> oldSamples;
1341                          creds->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK, oldSamples);
1342                          for (list<CssmSample>::iterator oit = oldSamples.begin(); oit != oldSamples.end(); oit++) {
1343                              TypedList &tmpList = *oit;
1344                              tmpList.checkProper();
1345                              if (tmpList.type() == CSSM_SAMPLE_TYPE_PASSWORD) {
1346                                  if (tmpList.length() == 2) {
1347                                      oldPassphrase = tmpList[1].data();
1348                                  }
1349                              }
1350                          }
1351                          if (!oldPassphrase.length() && mSecret && mSecret.length()) {
1352                              oldPassphrase = mSecret;
1353                          }
1354                          if ((oldPassphrase.length() == sample[1].data().length()) &&
1355                              !memcmp(oldPassphrase.data(), sample[1].data().data(), oldPassphrase.length()) &&
1356                              oldPassphrase.length()) {
1357                              // don't change master key if the passwords are the same
1358                              return false;
1359                          }
1360                          common().setup(NULL, sample[1]);
1361                          change_secret_on_keybag(*this, oldPassphrase.data(), (int)oldPassphrase.length(), sample[1].data().data(), (int)sample[1].data().length());
1362                      }
1363                      else {
1364                          common().setup(NULL, sample[1]);
1365                      }
1366                      return true;
1367                  }
1368  			// try to open with a given master key
1369  			case CSSM_WORDID_SYMMETRIC_KEY:
1370  			case CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY:
1371  				secinfo("KCdb", "%p specified explicit master key", this);
1372  				common().setup(NULL, keyFromCreds(sample, 3));
1373  				return true;
1374  			// explicitly defeat the default action but don't try anything in particular
1375  			case CSSM_WORDID_CANCELED:
1376  				secinfo("KCdb", "%p defeat default action", this);
1377  				break;
1378  			default:
1379  				// Unknown sub-sample for acquiring new secret.
1380  				// If we wanted to be fascist, we could now do
1381  				//  CssmError::throwMe(CSSM_ERRCODE_SAMPLE_VALUE_NOT_SUPPORTED);
1382  				// But instead we try to be tolerant and continue on.
1383  				// This DOES however count as an explicit attempt at specifying unlock,
1384  				// so we will no longer try the default case below...
1385  				secinfo("KCdb", "%p unknown sub-sample acquisition (%d) ignored",
1386  					this, sample.type());
1387  				break;
1388  			}
1389  		}
1390  	} else {
1391  		// default action -- interactive (only)
1392  		QueryNewPassphrase query(*this, reason);
1393  		StSyncLock<Mutex, Mutex> uisync(common().uiLock(), common());
1394          query.inferHints(Server::process());
1395  		CssmAutoData passphrase(Allocator::standard(Allocator::sensitive));
1396          CssmAutoData oldPassphrase(Allocator::standard(Allocator::sensitive));
1397          SecurityAgent::Reason reason(query(oldPassphrase, passphrase));
1398          uisync.unlock();
1399  		if (reason == SecurityAgent::noReason) {
1400              // If the DB was already unlocked then we have not yet checked the caller knows the old passphrase. Do so here.
1401              if (change && !validatePassphrase(oldPassphrase.get())) {
1402                  MacOSError::throwMe(errSecAuthFailed);
1403              }
1404  			common().setup(NULL, passphrase);
1405              change_secret_on_keybag(*this, oldPassphrase.data(), (int)oldPassphrase.length(), passphrase.data(), (int)passphrase.length());
1406  			return true;
1407  		}
1408  	}
1409  	
1410  	// out of options - no secret obtained
1411  	CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
1412  }
1413  
1414  
1415  //
1416  // Given a (truncated) Database credentials TypedList specifying a master key,
1417  // locate the key and return a reference to it.
1418  //
1419  CssmClient::Key KeychainDatabase::keyFromCreds(const TypedList &sample, unsigned int requiredLength)
1420  {
1421  	// decode TypedList structure (sample type; Data:CSPHandle; Data:CSSM_KEY)
1422  	assert(sample.type() == CSSM_SAMPLE_TYPE_SYMMETRIC_KEY || sample.type() == CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY);
1423  	if (sample.length() != requiredLength
1424  		|| sample[1].type() != CSSM_LIST_ELEMENT_DATUM
1425  		|| sample[2].type() != CSSM_LIST_ELEMENT_DATUM
1426  		|| (requiredLength == 4 && sample[3].type() != CSSM_LIST_ELEMENT_DATUM))
1427  			CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE);
1428  	KeyHandle &handle = *sample[1].data().interpretedAs<KeyHandle>(CSSM_ERRCODE_INVALID_SAMPLE_VALUE);
1429      // We used to be able to check the length but supporting multiple client
1430      // architectures dishes that (sizeof(CSSM_KEY) varies due to alignment and
1431      // field-size differences).  The decoding in the transition layer should 
1432      // serve as a sufficient garbling check anyway.  
1433      if (sample[2].data().data() == NULL)
1434          CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE);
1435      CssmKey &key = *sample[2].data().interpretedAs<CssmKey>();
1436  
1437  	if (key.header().cspGuid() == gGuidAppleCSPDL) {
1438  		// handleOrKey is a SecurityServer KeyHandle; ignore key argument
1439  		return safer_cast<LocalKey &>(*Server::key(handle));
1440  	} else 
1441  	if (sample.type() == CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY) {
1442  		/*
1443  			Contents (see DefaultCredentials::unlockKey in libsecurity_keychain/defaultcreds.cpp)
1444  			
1445  			sample[0]	sample type
1446  			sample[1]	csp handle for master or wrapping key; is really a keyhandle
1447  			sample[2]	masterKey [not used since securityd cannot interpret; use sample[1] handle instead]
1448  			sample[3]	UnlockReferralRecord data, in this case the flattened symmetric key
1449  		*/
1450  
1451  		// RefPointer<Key> Server::key(KeyHandle key)
1452  		KeyHandle keyhandle = *sample[1].data().interpretedAs<KeyHandle>(CSSM_ERRCODE_INVALID_SAMPLE_VALUE);
1453  		CssmData &flattenedKey = sample[3].data();
1454  		RefPointer<Key> unwrappingKey = Server::key(keyhandle);
1455  		Database &db=unwrappingKey->database();
1456  		
1457  		CssmKey rawWrappedKey;
1458  		unflattenKey(flattenedKey, rawWrappedKey);
1459  
1460  		RefPointer<Key> masterKey;
1461  		CssmData emptyDescriptiveData;
1462  		const AccessCredentials *cred = NULL;
1463  		const AclEntryPrototype *owner = NULL;
1464  		CSSM_KEYUSE usage = CSSM_KEYUSE_ANY;
1465  		CSSM_KEYATTR_FLAGS attrs = CSSM_KEYATTR_EXTRACTABLE;	//CSSM_KEYATTR_RETURN_REF | 
1466  
1467  		// Get default credentials for unwrappingKey (the one on the token)
1468  		// Copied from Statics::Statics() in libsecurity_keychain/aclclient.cpp
1469  		// Following KeyItem::getCredentials, one sees that the "operation" parameter
1470  		// e.g. "CSSM_ACL_AUTHORIZATION_DECRYPT" is ignored
1471  		Allocator &alloc = Allocator::standard();
1472  		AutoCredentials promptCred(alloc, 3);// enable interactive prompting
1473  	
1474  		// promptCred: a credential permitting user prompt confirmations
1475  		// contains:
1476  		//  a KEYCHAIN_PROMPT sample, both by itself and in a THRESHOLD
1477  		//  a PROMPTED_PASSWORD sample
1478  		promptCred.sample(0) = TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT);
1479  		promptCred.sample(1) = TypedList(alloc, CSSM_SAMPLE_TYPE_THRESHOLD,
1480  			new(alloc) ListElement(TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT)));
1481  		promptCred.sample(2) = TypedList(alloc, CSSM_SAMPLE_TYPE_PROMPTED_PASSWORD,
1482  			new(alloc) ListElement(alloc, CssmData()));
1483  
1484  		// This unwrap object is here just to provide a context
1485  		CssmClient::UnwrapKey unwrap(Server::csp(), CSSM_ALGID_NONE);	//ok to lie about csp here
1486  		unwrap.mode(CSSM_ALGMODE_NONE);
1487  		unwrap.padding(CSSM_PADDING_PKCS1);
1488  		unwrap.cred(promptCred);
1489  		unwrap.add(CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT, uint32(CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7));
1490  		Security::Context *tmpContext;
1491  		CSSM_CC_HANDLE CCHandle = unwrap.handle();
1492  		/*CSSM_RETURN rx = */ CSSM_GetContext (CCHandle, (CSSM_CONTEXT_PTR *)&tmpContext);
1493  		
1494  		// OK, this is skanky but necessary. We overwrite fields in the context struct
1495  
1496  		tmpContext->ContextType = CSSM_ALGCLASS_ASYMMETRIC;
1497  		tmpContext->AlgorithmType = CSSM_ALGID_RSA;
1498  		
1499  		db.unwrapKey(*tmpContext, cred, owner, unwrappingKey, NULL, usage, attrs,
1500  			rawWrappedKey, masterKey, emptyDescriptiveData);
1501  
1502  	    Allocator::standard().free(rawWrappedKey.KeyData.Data);
1503  
1504  		return safer_cast<LocalKey &>(*masterKey).key();
1505  	}
1506  	else if (sample.type() == CSSM_SAMPLE_TYPE_SYMMETRIC_KEY && sample.length() == 4 && sample[3].data().length() > 0) {
1507          /*
1508           Contents (see MasterKeyUnlockCredentials in libsecurity_cdsa_client/lib/aclclient.cpp)
1509  
1510           sample[0]  sample type
1511           sample[1]  0, since we don't have a valid handle
1512           sample[2]  CssmKey of the masterKey [can't immediately use since it includes a CSSM_DATA struct with pointers]
1513           sample[3]  flattened symmetric master key, including the key data
1514           */
1515  
1516          // Fix up key to include actual data
1517          CssmData &flattenedKey = sample[3].data();
1518          unflattenKey(flattenedKey, key);
1519  
1520          // Check that we have a reasonable key
1521          if (key.header().blobType() != CSSM_KEYBLOB_RAW) {
1522              CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE);
1523          }
1524          if (key.header().keyClass() != CSSM_KEYCLASS_SESSION_KEY) {
1525              CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
1526          }
1527  
1528          // bring the key into the CSP and return it
1529          return CssmClient::Key(Server::csp(), key, true);
1530      } else {
1531  		// not a KeyHandle reference; use key as a raw key
1532  		if (key.header().blobType() != CSSM_KEYBLOB_RAW)
1533  			CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE);
1534  		if (key.header().keyClass() != CSSM_KEYCLASS_SESSION_KEY)
1535  			CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
1536  		return CssmClient::Key(Server::csp(), key, true);
1537  	}
1538  }
1539  
1540  void unflattenKey(const CssmData &flatKey, CssmKey &rawKey)
1541  {
1542      // The format we're expecting is a CSSM_KEY followed by the actual key data:
1543      //    CSSM_KEY : KEY DATA
1544      // which is approximately:
1545      //    h2ni(CSSM_KEYHEADER) : 4 bytes padding : CSSM_DATA{?:?} : KEY BYTES
1546      //
1547      // Note that CSSM_KEY includes a CSSM_DATA struct, which we will ignore as it has pointers.
1548      // The pointer and length will be set to whatever key data follows the CSSM_KEY in rawKey.
1549  
1550  	// unflatten the raw input key naively: key header then key data
1551  	// We also convert it back to host byte order
1552  	// A CSSM_KEY is a CSSM_KEYHEADER followed by a CSSM_DATA
1553  
1554  	// Now copy: header, then key struct, then key data
1555  	memcpy(&rawKey.KeyHeader, flatKey.Data, sizeof(CSSM_KEYHEADER));
1556  	memcpy(&rawKey.KeyData, flatKey.Data + sizeof(CSSM_KEYHEADER), sizeof(CSSM_DATA));
1557  	size_t keyDataLength = flatKey.length() - sizeof(CSSM_KEY);
1558  	rawKey.KeyData.Data = Allocator::standard().malloc<uint8>(keyDataLength);
1559  	rawKey.KeyData.Length = keyDataLength;
1560  	memcpy(rawKey.KeyData.Data, flatKey.Data + sizeof(CSSM_KEY), keyDataLength);
1561  	Security::n2hi(rawKey.KeyHeader);	// convert it to host byte order
1562  }
1563  
1564  CssmClient::Key
1565  KeychainDatabase::keyFromKeybag(const TypedList &sample)
1566  {
1567      service_context_t context;
1568      uint8_t *session_key;
1569      int session_key_size;
1570      int rc;
1571      const struct ccmode_siv *mode = ccaes_siv_decrypt_mode();
1572      const size_t session_key_wrapped_len = 40;
1573      const size_t version_len = 1, nonce_len = 16;
1574      uint8_t *decrypted_data;
1575      size_t decrypted_len;
1576  
1577      assert(sample.type() == CSSM_SAMPLE_TYPE_KEYBAG_KEY);
1578  
1579      CssmData &unlock_token = sample[2].data();
1580  
1581      context = common().session().get_current_service_context();
1582      rc = service_client_kb_unwrap_key(&context, unlock_token.data(), session_key_wrapped_len, key_class_ak, (void **)&session_key, &session_key_size);
1583      if (rc != 0) {
1584          CssmError::throwMe(CSSM_ERRCODE_INVALID_CRYPTO_DATA);
1585      }
1586  
1587      uint8_t *indata = (uint8_t *)unlock_token.data() + session_key_wrapped_len;
1588      size_t inlen = unlock_token.length() - session_key_wrapped_len;
1589  
1590      decrypted_len = ccsiv_plaintext_size(mode, inlen - (version_len + nonce_len));
1591      decrypted_data = (uint8_t *)calloc(1, decrypted_len);
1592  
1593      ccsiv_ctx_decl(mode->size, ctx);
1594  
1595      rc = ccsiv_init(mode, ctx, session_key_size, session_key);
1596      if (rc != 0) CssmError::throwMe(CSSM_ERRCODE_INVALID_CRYPTO_DATA);
1597      rc = ccsiv_set_nonce(mode, ctx, nonce_len, indata + version_len);
1598      if (rc != 0) CssmError::throwMe(CSSM_ERRCODE_INVALID_CRYPTO_DATA);
1599      rc = ccsiv_aad(mode, ctx, 1, indata);
1600      if (rc != 0) CssmError::throwMe(CSSM_ERRCODE_INVALID_CRYPTO_DATA);
1601      rc = ccsiv_crypt(mode, ctx, inlen - (version_len + nonce_len), indata + version_len + nonce_len, decrypted_data);
1602      if (rc != 0) CssmError::throwMe(CSSM_ERRCODE_INVALID_CRYPTO_DATA);
1603  
1604      ccsiv_ctx_clear(mode->size, ctx);
1605  
1606      //free(decrypted_data);
1607      free(session_key);
1608      return makeRawKey(decrypted_data, decrypted_len, CSSM_ALGID_3DES_3KEY_EDE, CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT);
1609  }
1610  
1611  // adapted from DatabaseCryptoCore::makeRawKey
1612  CssmClient::Key KeychainDatabase::makeRawKey(void *data, size_t length,
1613      CSSM_ALGORITHMS algid, CSSM_KEYUSE usage)
1614  {
1615      // build a fake key
1616      CssmKey key;
1617      key.header().BlobType = CSSM_KEYBLOB_RAW;
1618      key.header().Format = CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING;
1619      key.header().AlgorithmId = algid;
1620      key.header().KeyClass = CSSM_KEYCLASS_SESSION_KEY;
1621      key.header().KeyUsage = usage;
1622      key.header().KeyAttr = 0;
1623      key.KeyData = CssmData(data, length);
1624  
1625      // unwrap it into the CSP (but keep it raw)
1626      CssmClient::UnwrapKey unwrap(Server::csp(), CSSM_ALGID_NONE);
1627      CssmKey unwrappedKey;
1628      CssmData descriptiveData;
1629      unwrap(key,
1630          CssmClient::KeySpec(CSSM_KEYUSE_ANY, CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE),
1631          unwrappedKey, &descriptiveData, NULL);
1632      return CssmClient::Key(Server::csp(), unwrappedKey);
1633  }
1634  
1635  //
1636  // Verify a putative database passphrase.
1637  // If the database is already unlocked, just check the passphrase.
1638  // Otherwise, unlock with that passphrase and report success.
1639  // Caller must hold the common lock.
1640  //
1641  bool KeychainDatabase::validatePassphrase(const CssmData &passphrase) const
1642  {
1643  	if (common().hasMaster()) {
1644  		// verify against known secret
1645  		return common().validatePassphrase(passphrase);
1646  	} else {
1647  		// no master secret - perform "blind" unlock to avoid actual unlock
1648  		try {
1649  			DatabaseCryptoCore test;
1650  			test.setup(mBlob, passphrase);
1651  			test.decodeCore(mBlob, NULL);
1652  			return true;
1653  		} catch (...) {
1654  			return false;
1655  		}
1656  	}
1657  }
1658  
1659  
1660  //
1661  // Lock this database
1662  //
1663  void KeychainDatabase::lockDb()
1664  {
1665      common().lockDb();
1666  }
1667  
1668  
1669  //
1670  // Given a Key for this database, encode it into a blob and return it.
1671  //
1672  KeyBlob *KeychainDatabase::encodeKey(const CssmKey &key, const CssmData &pubAcl, const CssmData &privAcl)
1673  {
1674  	bool inTheClear = false;
1675  	if((key.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY) &&
1676  	   !(key.attribute(CSSM_KEYATTR_PUBLIC_KEY_ENCRYPT))) {
1677  		inTheClear = true;
1678  	}
1679  	StLock<Mutex> _(common());
1680  	if(!inTheClear)
1681  		makeUnlocked(false);
1682  	
1683      // tell the cryptocore to form the key blob
1684      return common().encodeKeyCore(key, pubAcl, privAcl, inTheClear);
1685  }
1686  
1687  
1688  //
1689  // Given a "blobbed" key for this database, decode it into its real
1690  // key object and (re)populate its ACL.
1691  //
1692  void KeychainDatabase::decodeKey(KeyBlob *blob, CssmKey &key, void * &pubAcl, void * &privAcl)
1693  {
1694  	StLock<Mutex> _(common());
1695  
1696  	if(!blob->isClearText())
1697  		makeUnlocked(false);							// we need our keys
1698  
1699  	common().decodeKeyCore(blob, key, pubAcl, privAcl);
1700  	// memory protocol: pubAcl points into blob; privAcl was allocated
1701  	
1702      activity();
1703  }
1704  
1705  //
1706  // Given a KeychainKey (that implicitly belongs to another keychain), 
1707  // return it encoded using this keychain's operational secrets.  
1708  //
1709  KeyBlob *KeychainDatabase::recodeKey(KeychainKey &oldKey)
1710  {
1711  	if (mRecodingSource != &oldKey.referent<KeychainDatabase>()) {
1712          CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
1713      }
1714  
1715      // To protect this operation, we need to take the mutex for both our common and the remote key's common in some defined order.
1716      // Grab the common being cloned (oldKey's) first, and then the common receiving the recoding (ours).
1717      StLock<Mutex> _ (oldKey.referent<KeychainDatabase>().common());
1718      StLock<Mutex> __(common());
1719  
1720  	oldKey.instantiateAcl();	// make sure key is decoded
1721  	CssmData publicAcl, privateAcl;
1722  	oldKey.exportBlob(publicAcl, privateAcl);
1723  	// NB: blob's memory belongs to caller, not the common
1724  
1725  	/* 
1726  	 * Make sure the new key is in the same cleartext/encrypted state.
1727  	 */
1728  	bool inTheClear = false;
1729  	assert(oldKey.blob());
1730  	if(oldKey.blob() && oldKey.blob()->isClearText()) {
1731  		/* careful....*/
1732  		inTheClear = true;
1733  	}
1734  	KeyBlob *blob = common().encodeKeyCore(oldKey.cssmKey(), publicAcl, privateAcl, inTheClear);
1735  	oldKey.acl().allocator.free(publicAcl);
1736  	oldKey.acl().allocator.free(privateAcl);
1737  	return blob;
1738  }
1739  
1740  
1741  //
1742  // Modify database parameters
1743  //
1744  void KeychainDatabase::setParameters(const DBParameters &params)
1745  {
1746  	StLock<Mutex> _(common());
1747      makeUnlocked(false);
1748  	common().mParams = params;
1749      common().invalidateBlob();		// invalidate old blobs
1750      activity();				// (also resets the timeout timer)
1751  	secinfo("KCdb", "%p common %p(%s) set params=(%u,%u)",
1752  		this, &common(), dbName(), params.idleTimeout, params.lockOnSleep);
1753  }
1754  
1755  
1756  //
1757  // Retrieve database parameters
1758  //
1759  void KeychainDatabase::getParameters(DBParameters &params)
1760  {
1761  	StLock<Mutex> _(common());
1762      makeUnlocked(false);
1763  	params = common().mParams;
1764      //activity();		// getting parameters does not reset the idle timer
1765  }
1766  
1767  
1768  //
1769  // RIGHT NOW, database ACLs are attached to the database.
1770  // This will soon move upstairs.
1771  //
1772  SecurityServerAcl &KeychainDatabase::acl()
1773  {
1774  	return *this;
1775  }
1776  
1777  
1778  //
1779  // Intercept ACL change requests and reset blob validity
1780  //
1781  void KeychainDatabase::instantiateAcl()
1782  {
1783  	StLock<Mutex> _(common());
1784  	makeUnlocked(false);
1785  }
1786  
1787  void KeychainDatabase::changedAcl()
1788  {
1789  	StLock<Mutex> _(common());
1790  	version = 0;
1791  }
1792  
1793  
1794  //
1795  // Check an incoming DbBlob for basic viability
1796  //
1797  void KeychainDatabase::validateBlob(const DbBlob *blob)
1798  {
1799      // perform basic validation on the blob
1800  	assert(blob);
1801  	blob->validate(CSSMERR_APPLEDL_INVALID_DATABASE_BLOB);
1802  	if (blob->startCryptoBlob > blob->totalLength) {
1803  		CssmError::throwMe(CSSMERR_APPLEDL_INVALID_DATABASE_BLOB);
1804  	}
1805  	switch (blob->version()) {
1806  #if defined(COMPAT_OSX_10_0)
1807  		case DbBlob::version_MacOS_10_0:
1808  			break;
1809  #endif
1810  		case DbBlob::version_MacOS_10_1:
1811  			break;
1812  		case DbBlob::version_partition:
1813  			break;
1814  		default:
1815  			CssmError::throwMe(CSSMERR_APPLEDL_INCOMPATIBLE_DATABASE_BLOB);
1816  	}
1817  }
1818  
1819  //
1820  // Check if this database is currently recoding
1821  //
1822  bool KeychainDatabase::isRecoding()
1823  {
1824      secnotice("integrity", "recoding source: %p", mRecodingSource.get());
1825      return (mRecodingSource.get() != NULL || mRecoded);
1826  }
1827  
1828  //
1829  // Mark ourselves as no longer recoding
1830  //
1831  void KeychainDatabase::recodeFinished()
1832  {
1833      secnotice("integrity", "recoding finished");
1834      mRecodingSource = NULL;
1835      mRecoded = false;
1836  }
1837  
1838  
1839  //
1840  // Debugging support
1841  //
1842  #if defined(DEBUGDUMP)
1843  
1844  void KeychainDbCommon::dumpNode()
1845  {
1846  	PerSession::dumpNode();
1847  	uint32 sig; memcpy(&sig, &mIdentifier.signature(), sizeof(sig));
1848  	Debug::dump(" %s[%8.8x]", mIdentifier.dbName(), sig);
1849  	if (isLocked()) {
1850  		Debug::dump(" locked");
1851  	} else {
1852  		time_t whenTime = time_t(when());
1853  		Debug::dump(" unlocked(%24.24s/%.2g)", ctime(&whenTime),
1854  			(when() - Time::now()).seconds());
1855  	}
1856  	Debug::dump(" params=(%u,%u)", mParams.idleTimeout, mParams.lockOnSleep);
1857  }
1858  
1859  void KeychainDatabase::dumpNode()
1860  {
1861  	PerProcess::dumpNode();
1862  	Debug::dump(" %s vers=%u",
1863  		mValidData ? " data" : " nodata", version);
1864  	if (mBlob) {
1865  		uint32 sig; memcpy(&sig, &mBlob->randomSignature, sizeof(sig));
1866  		Debug::dump(" blob=%p[%8.8x]", mBlob, sig);
1867  	} else {
1868  		Debug::dump(" noblob");
1869  	}
1870  }
1871  
1872  #endif //DEBUGDUMP
1873  
1874  
1875  //
1876  // DbCommon basic features
1877  //
1878  KeychainDbCommon::KeychainDbCommon(Session &ssn, const DbIdentifier &id, uint32 requestedVersion)
1879  	: LocalDbCommon(ssn), DatabaseCryptoCore(requestedVersion), sequence(0), version(1), mIdentifier(id),
1880        mIsLocked(true), mValidParams(false), mLoginKeychain(false)
1881  {
1882      // match existing DbGlobal or create a new one
1883  	{
1884          Server &server = Server::active();
1885          StLock<Mutex> _(server);
1886          if (KeychainDbGlobal *dbglobal =
1887                  server.findFirst<KeychainDbGlobal, const DbIdentifier &>(&KeychainDbGlobal::identifier, identifier())) {
1888              parent(*dbglobal);
1889              secinfo("KCdb", "%p linking to existing DbGlobal %p", this, dbglobal);
1890          } else {
1891              // DbGlobal not present; make a new one
1892              parent(*new KeychainDbGlobal(identifier()));
1893              secinfo("KCdb", "%p linking to new DbGlobal %p", this, &global());
1894          }
1895  
1896          // link lifetime to the Session
1897          session().addReference(*this);
1898          
1899          if (strcasestr(id.dbName(), "login.keychain") != NULL) {
1900              mLoginKeychain = true;
1901          }
1902      }
1903  }
1904  
1905  void KeychainDbCommon::initializeKeybag() {
1906      if (mLoginKeychain && !session().keybagGetState(session_keybag_loaded)) {
1907          service_context_t context = session().get_current_service_context();
1908          if (service_client_kb_load(&context) == 0) {
1909              session().keybagSetState(session_keybag_loaded);
1910          }
1911      }
1912  }
1913  
1914  KeychainDbCommon::KeychainDbCommon(Session &ssn, const DbIdentifier &id, KeychainDbCommon& toClone)
1915      : LocalDbCommon(ssn), DatabaseCryptoCore(toClone.mBlobVersion), sequence(toClone.sequence), mParams(toClone.mParams), version(toClone.version),
1916      mIdentifier(id), mIsLocked(toClone.mIsLocked), mValidParams(toClone.mValidParams), mLoginKeychain(toClone.mLoginKeychain)
1917  {
1918      cloneFrom(toClone);
1919  
1920      {
1921          Server &server = Server::active();
1922          StLock<Mutex> _(server);
1923          if (KeychainDbGlobal *dbglobal =
1924              server.findFirst<KeychainDbGlobal, const DbIdentifier &>(&KeychainDbGlobal::identifier, identifier())) {
1925              parent(*dbglobal);
1926              secinfo("KCdb", "%p linking to existing DbGlobal %p", this, dbglobal);
1927          } else {
1928              // DbGlobal not present; make a new one
1929              parent(*new KeychainDbGlobal(identifier()));
1930              secinfo("KCdb", "%p linking to new DbGlobal %p", this, &global());
1931          }
1932          session().addReference(*this);
1933      }
1934  }
1935  
1936  KeychainDbCommon::~KeychainDbCommon()
1937  {
1938      secinfo("KCdb", "releasing keychain %p %s", this, (char*)this->dbName());
1939  
1940  	// explicitly unschedule ourselves
1941  	Server::active().clearTimer(this);
1942      if (mLoginKeychain) {
1943          session().keybagClearState(session_keybag_unlocked);
1944      }
1945      // remove ourselves from mCommonSet
1946      kill();
1947  }
1948  
1949  void KeychainDbCommon::cloneFrom(KeychainDbCommon& toClone, uint32 requestedVersion) {
1950      // don't clone the mIdentifier
1951      sequence = toClone.sequence;
1952      mParams = toClone.mParams;
1953      version = toClone.version;
1954      mIsLocked = toClone.mIsLocked;
1955      mValidParams = toClone.mValidParams;
1956      mLoginKeychain = toClone.mLoginKeychain;
1957  
1958      DatabaseCryptoCore::initializeFrom(toClone, requestedVersion);
1959  }
1960  
1961  void KeychainDbCommon::kill()
1962  {
1963      StReadWriteLock _(mRWCommonLock, StReadWriteLock::Write);
1964      mCommonSet.erase(this);
1965  }
1966  
1967  KeychainDbGlobal &KeychainDbCommon::global() const
1968  {
1969  	return parent<KeychainDbGlobal>();
1970  }
1971  
1972  
1973  void KeychainDbCommon::select()
1974  { this->ref(); }
1975  
1976  void KeychainDbCommon::unselect()
1977  { this->unref(); }
1978  
1979  
1980  
1981  void KeychainDbCommon::makeNewSecrets()
1982  {
1983  	// we already have a master key (right?)
1984  	assert(hasMaster());
1985  
1986  	// tell crypto core to generate the use keys
1987  	DatabaseCryptoCore::generateNewSecrets();
1988  	
1989  	// we're now officially "unlocked"; set the timer
1990  	setUnlocked();
1991  }
1992  
1993  
1994  //
1995  // All unlocking activity ultimately funnels through this method.
1996  // This unlocks a DbCommon using the secrets setup in its crypto core
1997  // component, and performs all the housekeeping needed to represent
1998  // the state change.
1999  // Returns true if unlock was successful, false if it failed due to
2000  // invalid/insufficient secrets. Throws on other errors.
2001  //
2002  bool KeychainDbCommon::unlockDb(DbBlob *blob, void **privateAclBlob)
2003  {
2004  	try {
2005  		// Tell the cryptocore to (try to) decode itself. This will fail
2006  		// in an astonishing variety of ways if the passphrase is wrong.
2007  		assert(hasMaster());
2008  		decodeCore(blob, privateAclBlob);
2009  		secinfo("KCdb", "%p unlock successful", this);
2010  	} catch (...) {
2011  		secinfo("KCdb", "%p unlock failed", this);
2012  		return false;
2013  	}
2014  	
2015  	// get the database parameters only if we haven't got them yet
2016  	if (!mValidParams) {
2017  		mParams = blob->params;
2018  		n2hi(mParams.idleTimeout);
2019  		mValidParams = true;	// sticky
2020  	}
2021  
2022  	bool isLocked = mIsLocked;
2023  	
2024  	setUnlocked();		// mark unlocked
2025  	
2026  	if (isLocked) {
2027  		// broadcast unlock notification, but only if we were previously locked
2028  		notify(kNotificationEventUnlocked);
2029          secinfo("KCdb", "unlocking keychain %p %s", this, (char*)this->dbName());
2030  	}
2031      return true;
2032  }
2033  
2034  void KeychainDbCommon::setUnlocked()
2035  {
2036  	session().addReference(*this);	// active/held
2037  	mIsLocked = false;				// mark unlocked
2038  	activity();						// set timeout timer
2039  }
2040  
2041  
2042  void KeychainDbCommon::lockDb()
2043  {
2044      {
2045          StLock<Mutex> _(*this);
2046          if (!isLocked()) {
2047              DatabaseCryptoCore::invalidate();
2048              notify(kNotificationEventLocked);
2049              secinfo("KCdb", "locking keychain %p %s", this, (char*)this->dbName());
2050              Server::active().clearTimer(this);
2051  
2052              mIsLocked = true;		// mark locked
2053              
2054              // this call may destroy us if we have no databases anymore
2055              session().removeReference(*this);
2056          }
2057      }
2058  }
2059  
2060  
2061  DbBlob *KeychainDbCommon::encode(KeychainDatabase &db)
2062  {
2063      assert(!isLocked());	// must have been unlocked by caller
2064      
2065      // export database ACL to blob form
2066      CssmData pubAcl, privAcl;
2067      db.acl().exportBlob(pubAcl, privAcl);
2068      
2069      // tell the cryptocore to form the blob
2070      DbBlob form;
2071      form.randomSignature = identifier();
2072      form.sequence = sequence;
2073      form.params = mParams;
2074  	h2ni(form.params.idleTimeout);
2075  	
2076  	assert(hasMaster());
2077      DbBlob *blob = encodeCore(form, pubAcl, privAcl);
2078      
2079      // clean up and go
2080      db.acl().allocator.free(pubAcl);
2081      db.acl().allocator.free(privAcl);
2082  	return blob;
2083  }
2084  
2085  
2086  //
2087  // Perform deferred lock processing for a database.
2088  //
2089  void KeychainDbCommon::action()
2090  {
2091  	secinfo("KCdb", "common %s(%p) locked by timer", dbName(), this);
2092  	lockDb();
2093  }
2094  
2095  void KeychainDbCommon::activity()
2096  {
2097      if (!isLocked()) {
2098  		secinfo("KCdb", "setting DbCommon %p timer to %d",
2099  			this, int(mParams.idleTimeout));
2100  		Server::active().setTimer(this, Time::Interval(int(mParams.idleTimeout)));
2101  	}
2102  }
2103  
2104  void KeychainDbCommon::sleepProcessing()
2105  {
2106  	secinfo("KCdb", "common %s(%p) sleep-lock processing", dbName(), this);
2107      if (mParams.lockOnSleep && !isDefaultSystemKeychain()) {
2108          StLock<Mutex> _(*this);
2109  		lockDb();
2110      }
2111  }
2112  
2113  void KeychainDbCommon::lockProcessing()
2114  {
2115  	lockDb();
2116  }
2117  
2118  
2119  //
2120  // We consider a keychain to belong to the system domain if it resides
2121  // in /Library/Keychains. That's not exactly fool-proof, but we don't
2122  // currently have any internal markers to interrogate.
2123  //
2124  bool KeychainDbCommon::belongsToSystem() const
2125  {
2126      if (const char *name = this->dbName())
2127          return !strncmp(name, "/Library/Keychains/", 19);
2128      return false;
2129  }
2130  
2131  bool KeychainDbCommon::isDefaultSystemKeychain() const
2132  {
2133      // /Library/Keychains/System.keychain (34)
2134      if (const char *name = this->dbName())
2135          return !strncmp(name, "/Library/Keychains/System.keychain", 34);
2136      return false;
2137  }
2138  
2139  //
2140  // Keychain global objects
2141  //
2142  KeychainDbGlobal::KeychainDbGlobal(const DbIdentifier &id)
2143  	: mIdentifier(id)
2144  {
2145  }
2146  
2147  KeychainDbGlobal::~KeychainDbGlobal()
2148  {
2149  	secinfo("KCdb", "DbGlobal %p destroyed", this);
2150  }