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 ¶ms, 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 ¶ms) 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 ¶ms) 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 }