2 * Copyright (c) 2000-2009,2012-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
26 // kcdatabase - software database container implementation.
28 // General implementation notes:
29 // This leverages LocalDatabase/LocalKey for cryptography, and adds the
30 // storage coder/decoder logic that implements "keychain" databases in their
31 // intricately choreographed dance between securityd and the AppleCSPDL.
32 // As always, Database objects are lifetime-bound to their Process referent;
33 // they can also be destroyed explicitly with a client release call.
34 // DbCommons are reference-held by their Databases, with one extra special
35 // reference (from the Session) introduced when the database unlocks, and
36 // removed when it locks again. That way, an unused DbCommon dies when it
37 // is locked or when the Session dies, whichever happens earlier.
38 // There is (as yet) no global-scope Database object for Keychain databases.
40 #include "kcdatabase.h"
41 #include "agentquery.h"
45 #include "notifications.h"
46 #include <vector> // @@@ 4003540 workaround
47 #include <security_cdsa_utilities/acl_any.h> // for default owner ACLs
48 #include <security_cdsa_utilities/cssmendian.h>
49 #include <security_cdsa_client/wrapkey.h>
50 #include <security_cdsa_client/genkey.h>
51 #include <security_cdsa_client/signclient.h>
52 #include <security_cdsa_client/cryptoclient.h>
53 #include <security_cdsa_client/macclient.h>
54 #include <securityd_client/dictionary.h>
55 #include <security_utilities/endian.h>
56 #include "securityd_service/securityd_service/securityd_service_client.h"
57 #include <AssertMacros.h>
59 #include <sys/sysctl.h>
60 #include <sys/kauth.h>
63 void unflattenKey(const CssmData
&flatKey
, CssmKey
&rawKey
); //>> make static method on KeychainDatabase
68 KeychainDbCommon::CommonSet
KeychainDbCommon::mCommonSet
;
69 ReadWriteLock
KeychainDbCommon::mRWCommonLock
;
71 // Process is using a cached effective uid, login window switches uid after the intial connection
72 static void get_process_euid(pid_t pid
, uid_t
* out_euid
)
74 if (!out_euid
) return;
76 struct kinfo_proc proc_info
= {};
77 int mib
[] = {CTL_KERN
, KERN_PROC
, KERN_PROC_PID
, pid
};
78 size_t len
= sizeof(struct kinfo_proc
);
80 ret
= sysctl(mib
, (sizeof(mib
)/sizeof(int)), &proc_info
, &len
, NULL
, 0);
83 if ((ret
== 0) && (proc_info
.kp_eproc
.e_ucred
.cr_uid
!= 0)) {
84 *out_euid
= proc_info
.kp_eproc
.e_ucred
.cr_uid
;
89 unlock_keybag(KeychainDatabase
& db
, const void * secret
, int secret_len
)
93 if (!db
.common().isLoginKeychain()) return 0;
95 service_context_t context
= db
.common().session().get_current_service_context();
97 // login window attempts to change the password before a session has a uid
98 if (context
.s_uid
== AU_DEFAUDITID
) {
99 get_process_euid(db
.process().pid(), &context
.s_uid
);
102 // try to unlock first if not found then load/create or unlock
103 // loading should happen when the kb common object is created
104 // if it doesn't exist yet then the unlock will fail and we'll create everything
105 rc
= service_client_kb_unlock(&context
, secret
, secret_len
);
106 if (rc
== KB_BagNotLoaded
) {
107 if (service_client_kb_load(&context
) == KB_BagNotFound
) {
108 rc
= service_client_kb_create(&context
, secret
, secret_len
);
110 rc
= service_client_kb_unlock(&context
, secret
, secret_len
);
114 if (rc
!= 0) { // if we just upgraded make sure we swap the encryption key to the password
115 if (!db
.common().session().keybagGetState(session_keybag_check_master_key
)) {
116 CssmAutoData
encKey(Allocator::standard(Allocator::sensitive
));
117 db
.common().get_encryption_key(encKey
);
118 if ((rc
= service_client_kb_unlock(&context
, encKey
.data(), (int)encKey
.length())) == 0) {
119 rc
= service_client_kb_change_secret(&context
, encKey
.data(), (int)encKey
.length(), secret
, secret_len
);
122 if (rc
!= 0) { // if a login.keychain password exists but doesnt on the keybag update it
124 if ((secret_len
> 0) && service_client_kb_is_locked(&context
, NULL
, &no_pin
) == 0) {
126 syslog(LOG_ERR
, "Updating iCloud keychain passphrase for uid %d", context
.s_uid
);
127 service_client_kb_change_secret(&context
, NULL
, 0, secret
, secret_len
);
131 } // session_keybag_check_master_key
135 db
.common().session().keybagSetState(session_keybag_unlocked
|session_keybag_loaded
|session_keybag_check_master_key
);
137 syslog(LOG_ERR
, "Failed to unlock iCloud keychain for uid %d", context
.s_uid
);
144 change_secret_on_keybag(KeychainDatabase
& db
, const void * secret
, int secret_len
, const void * new_secret
, int new_secret_len
)
146 if (!db
.common().isLoginKeychain()) return;
148 service_context_t context
= db
.common().session().get_current_service_context();
150 // login window attempts to change the password before a session has a uid
151 if (context
.s_uid
== AU_DEFAUDITID
) {
152 get_process_euid(db
.process().pid(), &context
.s_uid
);
155 // if a login.keychain doesn't exist yet it comes into securityd as a create then change_secret
156 // we need to create the keybag in this case if it doesn't exist
157 int rc
= service_client_kb_change_secret(&context
, secret
, secret_len
, new_secret
, new_secret_len
);
158 if (rc
== KB_BagNotLoaded
) {
159 if (service_client_kb_load(&context
) == KB_BagNotFound
) {
160 rc
= service_client_kb_create(&context
, new_secret
, new_secret_len
);
162 rc
= service_client_kb_change_secret(&context
, secret
, secret_len
, new_secret
, new_secret_len
);
166 // this makes it possible to restore a deleted keybag on condition it still exists in kernel
167 if (rc
!= KB_Success
) {
168 service_client_kb_save(&context
);
171 // if for some reason we are locked lets unlock so later we don't try and throw up SecurityAgent dialog
173 if ((service_client_kb_is_locked(&context
, &locked
, NULL
) == KB_Success
) && locked
) {
174 service_client_kb_unlock(&context
, new_secret
, new_secret_len
);
178 // Attempt to unlock the keybag with a AccessCredentials password.
179 // Honors UI disabled flags from clients set in the cred before prompt.
181 unlock_keybag_with_cred(KeychainDatabase
&db
, const AccessCredentials
*cred
){
182 list
<CssmSample
> samples
;
183 if (cred
&& cred
->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK
, samples
)) {
184 for (list
<CssmSample
>::iterator it
= samples
.begin(); it
!= samples
.end(); it
++) {
185 TypedList
&sample
= *it
;
186 sample
.checkProper();
187 switch (sample
.type()) {
188 // interactively prompt the user - no additional data
189 case CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT
: {
190 StSyncLock
<Mutex
, Mutex
> uisync(db
.common().uiLock(), db
.common());
191 // Once we get the ui lock, check whether another thread has already unlocked keybag
193 service_context_t context
= db
.common().session().get_current_service_context();
194 if ((service_client_kb_is_locked(&context
, &locked
, NULL
) == 0) && locked
) {
195 QueryKeybagPassphrase
keybagQuery(db
.common().session(), 3);
196 keybagQuery
.inferHints(Server::process());
197 if (keybagQuery
.query() == SecurityAgent::noReason
) {
202 // another thread already unlocked the keybag
207 // try to use an explicitly given passphrase - Data:passphrase
208 case CSSM_SAMPLE_TYPE_PASSWORD
: {
209 if (sample
.length() != 2)
210 CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
);
211 secinfo("KCdb", "attempting passphrase unlock of keybag");
212 if (unlock_keybag(db
, sample
[1].data().data(), (int)sample
[1].data().length())) {
218 // Unknown sub-sample for unlocking.
219 secinfo("KCdb", "keybag: unknown sub-sample unlock (%d) ignored", sample
.type());
229 // Create a Database object from initial parameters (create operation)
231 KeychainDatabase::KeychainDatabase(const DLDbIdentifier
&id
, const DBParameters
¶ms
, Process
&proc
,
232 const AccessCredentials
*cred
, const AclEntryPrototype
*owner
)
233 : LocalDatabase(proc
), mValidData(false), mSecret(Allocator::standard(Allocator::sensitive
)), mSaveSecret(false), version(0), mBlob(NULL
), mRecoded(false)
235 // save a copy of the credentials for later access control
236 mCred
= DataWalkers::copy(cred
, Allocator::standard());
238 // create a new random signature to complete the DLDbIdentifier
239 DbBlob::Signature newSig
;
240 Server::active().random(newSig
.bytes
);
241 DbIdentifier
ident(id
, newSig
);
243 // create common block and initialize
244 // Since this is a creation step, figure out the correct blob version for this database
245 RefPointer
<KeychainDbCommon
> newCommon
= new KeychainDbCommon(proc
.session(), ident
, CommonBlob::getCurrentVersionForDb(ident
.dbName()));
246 newCommon
->initializeKeybag();
248 StLock
<Mutex
> _(*newCommon
);
251 // new common is now visible (in ident-map) but we hold its lock
253 // establish the new master secret
254 establishNewSecrets(cred
, SecurityAgent::newDatabase
);
256 // set initial database parameters
257 common().mParams
= params
;
259 // the common is "unlocked" now
260 common().makeNewSecrets();
262 // establish initial ACL
264 acl().cssmSetInitial(*owner
);
266 acl().cssmSetInitial(new AnyAclSubject());
269 // for now, create the blob immediately
272 proc
.addReference(*this);
274 // this new keychain is unlocked; make it so
277 secinfo("KCdb", "creating keychain %p %s with common %p", this, (char*)this->dbName(), &common());
282 // Create a Database object from a database blob (decoding)
284 KeychainDatabase::KeychainDatabase(const DLDbIdentifier
&id
, const DbBlob
*blob
, Process
&proc
,
285 const AccessCredentials
*cred
)
286 : LocalDatabase(proc
), mValidData(false), mSecret(Allocator::standard(Allocator::sensitive
)), mSaveSecret(false), version(0), mBlob(NULL
), mRecoded(false)
290 // save a copy of the credentials for later access control
291 mCred
= DataWalkers::copy(cred
, Allocator::standard());
292 mBlob
= blob
->copy();
294 // check to see if we already know about this database
295 DbIdentifier
ident(id
, blob
->randomSignature
);
296 Session
&session
= process().session();
297 RefPointer
<KeychainDbCommon
> com
;
298 secnotice("kccommon", "looking for a common at %s", ident
.dbName());
299 if (KeychainDbCommon::find(ident
, session
, com
)) {
300 secnotice("kccommon", "found %p", com
.get());
302 secinfo("KCdb", "joining keychain %p %s with common %p", this, (char*)this->dbName(), &common());
304 // DbCommon not present; make a new one
305 secnotice("kccommon", "no common found");
307 common().mParams
= blob
->params
;
308 secinfo("KCdb", "making keychain %p %s with common %p", this, (char*)this->dbName(), &common());
309 // this DbCommon is locked; no timer or reference setting
311 proc
.addReference(*this);
314 void KeychainDbCommon::insert()
316 StReadWriteLock
_(mRWCommonLock
, StReadWriteLock::Write
);
320 void KeychainDbCommon::insertHoldingLock()
322 mCommonSet
.insert(this);
327 // find or make a DbCommon. Returns true if an existing one was found and used.
328 bool KeychainDbCommon::find(const DbIdentifier
&ident
, Session
&session
, RefPointer
<KeychainDbCommon
> &common
, uint32 requestedVersion
, KeychainDbCommon
* cloneFrom
)
330 // Prepare to drop the mRWCommonLock.
332 StReadWriteLock
_(mRWCommonLock
, StReadWriteLock::Read
);
333 for (CommonSet::const_iterator it
= mCommonSet
.begin(); it
!= mCommonSet
.end(); ++it
) {
334 if (&session
== &(*it
)->session() && ident
== (*it
)->identifier()) {
336 secnotice("kccommon", "found a common for %s at %p", ident
.dbName(), common
.get());
342 // not found. Grab the write lock, ensure that nobody has beaten us to adding,
343 // and then create a DbCommon and add it to the map.
345 StReadWriteLock
_(mRWCommonLock
, StReadWriteLock::Write
);
346 for (CommonSet::const_iterator it
= mCommonSet
.begin(); it
!= mCommonSet
.end(); ++it
) {
347 if (&session
== &(*it
)->session() && ident
== (*it
)->identifier()) {
349 secnotice("kccommon", "found a common for %s at %p", ident
.dbName(), common
.get());
356 common
= new KeychainDbCommon(session
, ident
, *cloneFrom
);
357 } else if(requestedVersion
!= CommonBlob::version_none
) {
358 common
= new KeychainDbCommon(session
, ident
, requestedVersion
);
360 common
= new KeychainDbCommon(session
, ident
);
363 secnotice("kccommon", "made a new common for %s at %p", ident
.dbName(), common
.get());
365 // Can't call insert() here, because it grabs the write lock (which we have).
366 common
->insertHoldingLock();
368 common
->initializeKeybag();
374 // Special-purpose constructor for keychain synchronization. Copies an
375 // existing keychain but uses the operational keys from secretsBlob. The
376 // new KeychainDatabase will silently replace the existing KeychainDatabase
377 // as soon as the client declares that re-encoding of all keychain items is
378 // finished. This is a little perilous since it allows a client to dictate
379 // securityd state, but we try to ensure that only the client that started
380 // the re-encoding can declare it done.
382 KeychainDatabase::KeychainDatabase(KeychainDatabase
&src
, Process
&proc
, DbHandle dbToClone
)
383 : LocalDatabase(proc
), mValidData(false), mSecret(Allocator::standard(Allocator::sensitive
)), mSaveSecret(false), version(0), mBlob(NULL
), mRecoded(false)
385 mCred
= DataWalkers::copy(src
.mCred
, Allocator::standard());
387 // Give this KeychainDatabase a temporary name
388 std::string newDbName
= std::string("////") + std::string(src
.identifier().dbName());
389 DLDbIdentifier
newDLDbIdent(src
.identifier().dlDbIdentifier().ssuid(), newDbName
.c_str(), src
.identifier().dlDbIdentifier().dbLocation());
390 DbIdentifier
ident(newDLDbIdent
, src
.identifier());
392 // create common block and initialize
393 RefPointer
<KeychainDbCommon
> newCommon
= new KeychainDbCommon(proc
.session(), ident
);
394 newCommon
->initializeKeybag();
395 StLock
<Mutex
> _(*newCommon
);
399 // set initial database parameters from the source keychain
400 common().mParams
= src
.common().mParams
;
402 // establish the source keychain's master secret as ours
403 // @@@ NB: this is a v. 0.1 assumption. We *should* trigger new UI
404 // that offers the user the option of using the existing password
405 // or choosing a new one. That would require a new
406 // SecurityAgentQuery type, new UI, and--possibly--modifications to
407 // ensure that the new password is available here to generate the
408 // new master secret.
409 src
.unlockDb(false); // precaution for masterKey()
410 common().setup(src
.blob(), src
.common().masterKey());
412 // import the operational secrets
413 RefPointer
<KeychainDatabase
> srcKC
= Server::keychain(dbToClone
);
414 common().importSecrets(srcKC
->common());
416 // import source keychain's ACL
417 CssmData pubAcl
, privAcl
;
418 src
.acl().exportBlob(pubAcl
, privAcl
);
419 importBlob(pubAcl
.data(), privAcl
.data());
420 src
.acl().allocator
.free(pubAcl
);
421 src
.acl().allocator
.free(privAcl
);
423 // indicate that this keychain should be allowed to do some otherwise
424 // risky things required for copying, like re-encoding keys
425 mRecodingSource
= &src
;
427 common().setUnlocked();
432 proc
.addReference(*this);
433 secinfo("SSdb", "database %s(%p) created as copy, common at %p",
434 common().dbName(), this, &common());
437 // Make a new KeychainDatabase from an old one, but have a completely different location
438 KeychainDatabase::KeychainDatabase(const DLDbIdentifier
& id
, KeychainDatabase
&src
, Process
&proc
)
439 : LocalDatabase(proc
), mValidData(false), mSecret(Allocator::standard(Allocator::sensitive
)), mSaveSecret(false), version(0), mBlob(NULL
), mRecoded(false)
441 mCred
= DataWalkers::copy(src
.mCred
, Allocator::standard());
443 DbIdentifier
ident(id
, src
.identifier());
445 // create common block and initialize
446 RefPointer
<KeychainDbCommon
> newCommon
;
447 if(KeychainDbCommon::find(ident
, process().session(), newCommon
, CommonBlob::version_none
, &src
.common())) {
448 // A common already existed. Write over it, but note that everything may go horribly from here on out.
449 secnotice("kccommon", "Found common where we didn't expect. Possible strange behavior ahead.");
450 newCommon
->cloneFrom(src
.common());
453 StLock
<Mutex
> _(*newCommon
);
456 // set initial database parameters from the source keychain
457 common().mParams
= src
.common().mParams
;
459 // import source keychain's ACL
460 CssmData pubAcl
, privAcl
;
461 src
.acl().exportBlob(pubAcl
, privAcl
);
462 importBlob(pubAcl
.data(), privAcl
.data());
463 src
.acl().allocator
.free(pubAcl
);
464 src
.acl().allocator
.free(privAcl
);
466 // Copy the source database's blob, if possible
468 mBlob
= src
.mBlob
->copy();
469 version
= src
.version
;
472 // We've copied everything we can from our source. If they were valid, so are we.
473 mValidData
= src
.mValidData
;
475 proc
.addReference(*this);
476 secinfo("SSdb", "database %s(%p) created as expected clone, common at %p", common().dbName(), this, &common());
480 // Make a new KeychainDatabase from an old one, but have entirely new operational secrets
481 KeychainDatabase::KeychainDatabase(uint32 requestedVersion
, KeychainDatabase
&src
, Process
&proc
)
482 : LocalDatabase(proc
), mValidData(false), mSecret(Allocator::standard(Allocator::sensitive
)), mSaveSecret(false), version(0), mBlob(NULL
), mRecoded(false)
484 mCred
= DataWalkers::copy(src
.mCred
, Allocator::standard());
486 // Give this KeychainDatabase a temporary name
487 // this must canonicalize to a different path than the original DB, otherwise another process opening the existing DB wil find this new KeychainDbCommon
488 // and call decodeCore with the old blob, overwriting the new secrets and wreaking havoc
489 std::string newDbName
= std::string("////") + std::string(src
.identifier().dbName()) + std::string("_com.apple.security.keychain.migrating");
490 DLDbIdentifier
newDLDbIdent(src
.identifier().dlDbIdentifier().ssuid(), newDbName
.c_str(), src
.identifier().dlDbIdentifier().dbLocation());
491 DbIdentifier
ident(newDLDbIdent
, src
.identifier());
493 // hold the lock for src's common during this operation (to match locking common locking order with KeychainDatabase::recodeKey)
494 StLock
<Mutex
> __(src
.common());
496 // create common block and initialize
497 RefPointer
<KeychainDbCommon
> newCommon
;
498 if(KeychainDbCommon::find(ident
, process().session(), newCommon
, requestedVersion
)) {
499 // A common already existed here. Write over it, but note that everything may go horribly from here on out.
500 secnotice("kccommon", "Found common where we didn't expect. Possible strange behavior ahead.");
501 newCommon
->cloneFrom(src
.common(), requestedVersion
);
503 newCommon
->initializeKeybag();
504 StLock
<Mutex
> _(*newCommon
);
507 // We want to re-use the master secrets from the source database (and so the
508 // same password), but reroll new operational secrets.
510 // Copy the master secret over...
511 src
.unlockDb(false); // precaution
513 common().setup(src
.blob(), src
.common().masterKey(), false); // keep the new common's version intact
515 // set initial database parameters from the source keychain
516 common().mParams
= src
.common().mParams
;
518 // and make new operational secrets
519 common().makeNewSecrets();
521 // import source keychain's ACL
522 CssmData pubAcl
, privAcl
;
523 src
.acl().exportBlob(pubAcl
, privAcl
);
524 importBlob(pubAcl
.data(), privAcl
.data());
525 src
.acl().allocator
.free(pubAcl
);
526 src
.acl().allocator
.free(privAcl
);
528 // indicate that this keychain should be allowed to do some otherwise
529 // risky things required for copying, like re-encoding keys
530 mRecodingSource
= &src
;
532 common().setUnlocked();
537 proc
.addReference(*this);
538 secinfo("SSdb", "database %s(%p) created as expected copy, common at %p",
539 common().dbName(), this, &common());
543 // Destroy a Database
545 KeychainDatabase::~KeychainDatabase()
547 secinfo("KCdb", "deleting database %s(%p) common %p",
548 common().dbName(), this, &common());
549 Allocator::standard().free(mCred
);
550 Allocator::standard().free(mBlob
);
555 // Basic Database virtual implementations
557 KeychainDbCommon
&KeychainDatabase::common() const
559 return parent
<KeychainDbCommon
>();
562 const char *KeychainDatabase::dbName() const
564 return common().dbName();
567 bool KeychainDatabase::transient() const
569 return false; // has permanent store
572 AclKind
KeychainDatabase::aclKind() const
577 Database
*KeychainDatabase::relatedDatabase()
583 // (Re-)Authenticate the database. This changes the stored credentials.
585 void KeychainDatabase::authenticate(CSSM_DB_ACCESS_TYPE mode
,
586 const AccessCredentials
*cred
)
588 StLock
<Mutex
> _(common());
590 // the (Apple specific) RESET bit means "lock the database now"
592 case CSSM_DB_ACCESS_RESET
:
593 secinfo("KCdb", "%p ACCESS_RESET triggers keychain lock", this);
597 // store the new credentials for future use
598 secinfo("KCdb", "%p authenticate stores new database credentials", this);
599 AccessCredentials
*newCred
= DataWalkers::copy(cred
, Allocator::standard());
600 Allocator::standard().free(mCred
);
607 // Make a new KeychainKey.
608 // If PERMANENT is off, make a temporary key instead.
609 // The db argument allows you to create for another KeychainDatabase (only);
610 // it defaults to ourselves.
612 RefPointer
<Key
> KeychainDatabase::makeKey(Database
&db
, const CssmKey
&newKey
,
613 uint32 moreAttributes
, const AclEntryPrototype
*owner
)
616 if (moreAttributes
& CSSM_KEYATTR_PERMANENT
)
617 return new KeychainKey(db
, newKey
, moreAttributes
, owner
);
619 return process().makeTemporaryKey(newKey
, moreAttributes
, owner
);
622 RefPointer
<Key
> KeychainDatabase::makeKey(const CssmKey
&newKey
,
623 uint32 moreAttributes
, const AclEntryPrototype
*owner
)
625 return makeKey(*this, newKey
, moreAttributes
, owner
);
630 // Return the database blob, recalculating it as needed.
632 DbBlob
*KeychainDatabase::blob()
634 StLock
<Mutex
> _(common());
636 makeUnlocked(false); // unlock to get master secret
637 encode(); // (re)encode blob if needed
639 activity(); // reset timeout
640 assert(validBlob()); // better have a valid blob now...
646 // Encode the current database as a blob.
647 // Note that this returns memory we own and keep.
648 // Caller must hold common lock.
650 void KeychainDatabase::encode()
652 DbBlob
*blob
= common().encode(*this);
653 Allocator::standard().free(mBlob
);
655 version
= common().version
;
656 secinfo("KCdb", "encoded database %p common %p(%s) version %u params=(%u,%u)",
657 this, &common(), dbName(), version
,
658 common().mParams
.idleTimeout
, common().mParams
.lockOnSleep
);
663 // Change the passphrase on a database
665 void KeychainDatabase::changePassphrase(const AccessCredentials
*cred
)
667 // get and hold the common lock (don't let other threads break in here)
668 StLock
<Mutex
> _(common());
670 // establish OLD secret - i.e. unlock the database
671 //@@@ do we want to leave the final lock state alone?
672 if (common().isLoginKeychain()) mSaveSecret
= true;
673 makeUnlocked(cred
, false);
675 // establish NEW secret
676 if(!establishNewSecrets(cred
, SecurityAgent::changePassphrase
)) {
677 secinfo("KCdb", "Old and new passphrases are the same. Database %s(%p) master secret did not change.",
678 common().dbName(), this);
681 if (mSecret
) { mSecret
.reset(); }
683 common().invalidateBlob(); // blob state changed
684 secinfo("KCdb", "Database %s(%p) master secret changed", common().dbName(), this);
685 encode(); // force rebuild of local blob
687 // send out a notification
688 notify(kNotificationEventPassphraseChanged
);
690 // I guess this counts as an activity
695 // Second stage of keychain synchronization: overwrite the original keychain's
696 // (this KeychainDatabase's) operational secrets
698 void KeychainDatabase::commitSecretsForSync(KeychainDatabase
&cloneDb
)
700 StLock
<Mutex
> _(common());
702 // try to detect spoofing
703 if (cloneDb
.mRecodingSource
!= this)
704 CssmError::throwMe(CSSM_ERRCODE_INVALID_DB_HANDLE
);
706 // in case we autolocked since starting the sync
707 makeUnlocked(false); // call this because we already own the lock
708 cloneDb
.unlockDb(false); // we may not own the lock here, so calling unlockDb will lock the cloneDb's common lock
710 // Decode all keys whose handles refer to this on-disk keychain so that
711 // if the holding client commits the key back to disk, it's encoded with
712 // the new operational secrets. The recoding client *must* hold a write
713 // lock for the on-disk keychain from the moment it starts recoding key
714 // items until after this call.
716 // @@@ This specific implementation is a workaround for 4003540.
717 std::vector
<U32HandleObject::Handle
> handleList
;
718 U32HandleObject::findAllRefs
<KeychainKey
>(handleList
);
719 size_t count
= handleList
.size();
721 for (unsigned int n
= 0; n
< count
; ++n
) {
722 RefPointer
<KeychainKey
> kckey
=
723 U32HandleObject::findRefAndLock
<KeychainKey
>(handleList
[n
], CSSMERR_CSP_INVALID_KEY_REFERENCE
);
724 StLock
<Mutex
> _(*kckey
/*, true*/);
725 if (kckey
->database().global().identifier() == identifier()) {
726 kckey
->key(); // force decode
727 kckey
->invalidateBlob();
728 secinfo("kcrecode", "changed extant key %p (proc %d)",
729 &*kckey
, kckey
->process().pid());
734 // mark down that we just recoded
737 // it is now safe to replace the old op secrets
738 common().importSecrets(cloneDb
.common());
739 common().invalidateBlob();
744 // Extract the database master key as a proper Key object.
746 RefPointer
<Key
> KeychainDatabase::extractMasterKey(Database
&db
,
747 const AccessCredentials
*cred
, const AclEntryPrototype
*owner
,
748 uint32 usage
, uint32 attrs
)
750 // get and hold common lock
751 StLock
<Mutex
> _(common());
753 // force lock to require re-validation of credentials
756 // unlock to establish master secret
759 // extract the raw cryptographic key
760 CssmClient::WrapKey
wrap(Server::csp(), CSSM_ALGID_NONE
);
762 wrap(common().masterKey(), key
);
764 // make the key object and return it
765 return makeKey(db
, key
, attrs
& LocalKey::managedAttributes
, owner
);
770 // Unlock this database (if needed) by obtaining the master secret in some
771 // suitable way and then proceeding to unlock with it.
772 // Does absolutely nothing if the database is already unlocked.
773 // The makeUnlocked forms are identical except the assume the caller already
774 // holds the common lock.
776 void KeychainDatabase::unlockDb(bool unlockKeybag
)
778 StLock
<Mutex
> _(common());
779 makeUnlocked(unlockKeybag
);
782 void KeychainDatabase::makeUnlocked(bool unlockKeybag
)
784 return makeUnlocked(mCred
, unlockKeybag
);
787 void KeychainDatabase::makeUnlocked(const AccessCredentials
*cred
, bool unlockKeybag
)
790 secinfo("KCdb", "%p(%p) unlocking for makeUnlocked()", this, &common());
791 assert(mBlob
|| (mValidData
&& common().hasMaster()));
792 establishOldSecrets(cred
);
793 common().setUnlocked(); // mark unlocked
794 if (common().isLoginKeychain()) {
795 CssmKey master
= common().masterKey();
797 CssmClient::WrapKey
wrap(Server::csp(), CSSM_ALGID_NONE
);
798 wrap(master
, rawMaster
);
800 service_context_t context
= common().session().get_current_service_context();
801 service_client_stash_load_key(&context
, rawMaster
.keyData(), (int)rawMaster
.length());
803 } else if (unlockKeybag
&& common().isLoginKeychain()) {
805 service_context_t context
= common().session().get_current_service_context();
806 if ((service_client_kb_is_locked(&context
, &locked
, NULL
) == 0) && locked
) {
807 if (!unlock_keybag_with_cred(*this, cred
)) {
808 syslog(LOG_NOTICE
, "failed to unlock iCloud keychain");
812 if (!mValidData
) { // need to decode to get our ACLs, master secret available
813 secinfo("KCdb", "%p(%p) is unlocked; decoding for makeUnlocked()", this, &common());
815 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
);
822 // Invoke the securityd_service to retrieve the keychain master
823 // key from the AppleFDEKeyStore.
825 void KeychainDatabase::stashDbCheck()
827 CssmAutoData
masterKey(Allocator::standard(Allocator::sensitive
));
828 CssmAutoData
encKey(Allocator::standard(Allocator::sensitive
));
832 void * stash_key
= NULL
;
833 int stash_key_len
= 0;
834 service_context_t context
= common().session().get_current_service_context();
835 rc
= service_client_stash_get_key(&context
, &stash_key
, &stash_key_len
);
838 masterKey
.copy(CssmData((void *)stash_key
,stash_key_len
));
839 memset(stash_key
, 0, stash_key_len
);
843 CssmError::throwMe(rc
);
847 StLock
<Mutex
> _(common());
849 // Now establish it as the keychain master key
850 CssmClient::Key
key(Server::csp(), masterKey
.get());
851 CssmKey::Header
&hdr
= key
.header();
852 hdr
.keyClass(CSSM_KEYCLASS_SESSION_KEY
);
853 hdr
.algorithm(CSSM_ALGID_3DES_3KEY_EDE
);
854 hdr
.usage(CSSM_KEYUSE_ANY
);
855 hdr
.blobType(CSSM_KEYBLOB_RAW
);
856 hdr
.blobFormat(CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING
);
857 common().setup(mBlob
, key
);
860 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
);
862 common().get_encryption_key(encKey
);
865 // when upgrading from pre-10.9 create a keybag if it doesn't exist with the encryption key
866 // only do this after we have verified the master key unlocks the login.keychain
867 if (service_client_kb_load(&context
) == KB_BagNotFound
) {
868 service_client_kb_create(&context
, encKey
.data(), (int)encKey
.length());
873 // Get the keychain master key and invoke the securityd_service
874 // to stash it in the AppleFDEKeyStore ready for commit to the
877 void KeychainDatabase::stashDb()
879 CssmAutoData
data(Allocator::standard(Allocator::sensitive
));
882 StLock
<Mutex
> _(common());
884 if (!common().isValid()) {
885 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
888 CssmKey key
= common().masterKey();
889 data
.copy(key
.keyData());
892 service_context_t context
= common().session().get_current_service_context();
893 int rc
= service_client_stash_set_key(&context
, data
.data(), (int)data
.length());
894 if (rc
!= 0) CssmError::throwMe(rc
);
898 // The following unlock given an explicit passphrase, rather than using
899 // (special cred sample based) default procedures.
901 void KeychainDatabase::unlockDb(const CssmData
&passphrase
, bool unlockKeybag
)
903 StLock
<Mutex
> _(common());
904 makeUnlocked(passphrase
, unlockKeybag
);
907 void KeychainDatabase::makeUnlocked(const CssmData
&passphrase
, bool unlockKeybag
)
910 if (decode(passphrase
))
913 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
);
914 } else if (!mValidData
) { // need to decode to get our ACLs, passphrase available
916 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
);
919 if (unlockKeybag
&& common().isLoginKeychain()) {
921 service_context_t context
= common().session().get_current_service_context();
922 if (!common().session().keybagGetState(session_keybag_check_master_key
) || ((service_client_kb_is_locked(&context
, &locked
, NULL
) == 0) && locked
)) {
923 unlock_keybag(*this, passphrase
.data(), (int)passphrase
.length());
933 // Nonthrowing passphrase-based unlock. This returns false if unlock failed.
934 // Note that this requires an explicitly given passphrase.
935 // Caller must hold common lock.
937 bool KeychainDatabase::decode(const CssmData
&passphrase
)
940 common().setup(mBlob
, passphrase
);
941 bool success
= decode();
942 if (success
&& common().isLoginKeychain()) {
943 unlock_keybag(*this, passphrase
.data(), (int)passphrase
.length());
950 // Given the established master secret, decode the working keys and other
951 // functional secrets for this database. Return false (do NOT throw) if
952 // the decode fails. Call this in low(er) level code once you established
955 bool KeychainDatabase::decode()
958 assert(common().hasMaster());
959 void *privateAclBlob
;
960 if (common().unlockDb(mBlob
, &privateAclBlob
)) {
962 acl().importBlob(mBlob
->publicAclBlob(), privateAclBlob
);
965 Allocator::standard().free(privateAclBlob
);
968 secinfo("KCdb", "%p decode failed", this);
974 // Given an AccessCredentials for this database, wring out the existing primary
975 // database secret by whatever means necessary.
976 // On entry, caller must hold the database common lock. It will be held
977 // throughout except when user interaction is required. User interaction
978 // requires relinquishing the database common lock and taking the UI lock. On
979 // return from user interaction, the UI lock is relinquished and the database
980 // common lock must be reacquired. At no time may the caller hold both locks.
981 // On exit, the crypto core has its master secret. If things go wrong,
982 // we will throw a suitable exception. Note that encountering any malformed
983 // credential sample will throw, but this is not guaranteed -- don't assume
984 // that NOT throwing means creds is entirely well-formed (it may just be good
985 // enough to work THIS time).
988 // Walk through the creds. Fish out those credentials (in order) that
989 // are for unlock processing (they have no ACL subject correspondents),
990 // and (try to) obey each in turn, until one produces a valid secret
991 // or you run out. If no special samples are found at all, interpret that as
992 // "use the system global default," which happens to be hard-coded right here.
994 void KeychainDatabase::establishOldSecrets(const AccessCredentials
*creds
)
996 bool forSystem
= this->belongsToSystem(); // this keychain belongs to the system security domain
998 // attempt system-keychain unlock
1000 SystemKeychainKey
systemKeychain(kSystemUnlockFile
);
1001 if (systemKeychain
.matches(mBlob
->randomSignature
)) {
1002 secinfo("KCdb", "%p attempting system unlock", this);
1003 common().setup(mBlob
, CssmClient::Key(Server::csp(), systemKeychain
.key(), true));
1009 list
<CssmSample
> samples
;
1010 if (creds
&& creds
->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK
, samples
)) {
1011 for (list
<CssmSample
>::iterator it
= samples
.begin(); it
!= samples
.end(); it
++) {
1012 TypedList
&sample
= *it
;
1013 sample
.checkProper();
1014 switch (sample
.type()) {
1015 // interactively prompt the user - no additional data
1016 case CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT
:
1018 if (interactiveUnlock())
1022 // try to use an explicitly given passphrase - Data:passphrase
1023 case CSSM_SAMPLE_TYPE_PASSWORD
:
1024 if (sample
.length() != 2)
1025 CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
);
1026 secinfo("KCdb", "%p attempting passphrase unlock", this);
1027 if (decode(sample
[1]))
1030 // try to open with a given master key - Data:CSP or KeyHandle, Data:CssmKey
1031 case CSSM_SAMPLE_TYPE_SYMMETRIC_KEY
:
1032 case CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY
:
1034 secinfo("KCdb", "%p attempting explicit key unlock", this);
1035 common().setup(mBlob
, keyFromCreds(sample
, 4));
1040 // explicitly defeat the default action but don't try anything in particular
1041 case CSSM_WORDID_CANCELED
:
1042 secinfo("KCdb", "%p defeat default action", this);
1045 // Unknown sub-sample for unlocking.
1046 // If we wanted to be fascist, we could now do
1047 // CssmError::throwMe(CSSM_ERRCODE_SAMPLE_VALUE_NOT_SUPPORTED);
1048 // But instead we try to be tolerant and continue on.
1049 // This DOES however count as an explicit attempt at specifying unlock,
1050 // so we will no longer try the default case below...
1051 secinfo("KCdb", "%p unknown sub-sample unlock (%d) ignored", this, sample
.type());
1060 if (interactiveUnlock())
1065 // out of options - no secret obtained
1066 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
);
1070 // This function is almost identical to establishOldSecrets, but:
1071 // 1. It will never prompt the user; these credentials either work or they don't
1072 // 2. It will not change the secrets of this database
1074 // TODO: These two functions should probably be refactored to something nicer.
1075 bool KeychainDatabase::checkCredentials(const AccessCredentials
*creds
) {
1077 list
<CssmSample
> samples
;
1078 if (creds
&& creds
->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK
, samples
)) {
1079 for (list
<CssmSample
>::iterator it
= samples
.begin(); it
!= samples
.end(); it
++) {
1080 TypedList
&sample
= *it
;
1081 sample
.checkProper();
1082 switch (sample
.type()) {
1083 // interactively prompt the user - no additional data
1084 case CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT
:
1085 // do nothing, because this function will never prompt the user
1086 secinfo("integrity", "%p ignoring keychain prompt", this);
1088 // try to use an explicitly given passphrase - Data:passphrase
1089 case CSSM_SAMPLE_TYPE_PASSWORD
:
1090 if (sample
.length() != 2)
1091 CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
);
1092 secinfo("integrity", "%p checking passphrase", this);
1093 if(validatePassphrase(sample
[1])) {
1097 // try to open with a given master key - Data:CSP or KeyHandle, Data:CssmKey
1098 case CSSM_SAMPLE_TYPE_SYMMETRIC_KEY
:
1099 case CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY
:
1101 secinfo("integrity", "%p attempting explicit key unlock", this);
1103 CssmClient::Key checkKey
= keyFromCreds(sample
, 4);
1104 if(common().validateKey(checkKey
)) {
1108 // ignore all problems in keyFromCreds
1109 secinfo("integrity", "%p caught error", this);
1116 // out of options - credentials don't match
1120 uint32_t KeychainDatabase::interactiveUnlockAttempts
= 0;
1122 bool KeychainDatabase::interactiveUnlock()
1124 secinfo("KCdb", "%p attempting interactive unlock", this);
1125 interactiveUnlockAttempts
++;
1127 SecurityAgent::Reason reason
= SecurityAgent::noReason
;
1128 QueryUnlock
query(*this);
1129 // take UI interlock and release DbCommon lock (to avoid deadlocks)
1130 StSyncLock
<Mutex
, Mutex
> uisync(common().uiLock(), common());
1132 // now that we have the UI lock, interact unless another thread unlocked us first
1134 query
.inferHints(Server::process());
1136 if (mSaveSecret
&& reason
== SecurityAgent::noReason
) {
1137 query
.retrievePassword(mSecret
);
1141 secinfo("KCdb", "%p was unlocked during uiLock delay", this);
1144 if (common().isLoginKeychain()) {
1145 bool locked
= false;
1146 service_context_t context
= common().session().get_current_service_context();
1147 if ((service_client_kb_is_locked(&context
, &locked
, NULL
) == 0) && locked
) {
1148 QueryKeybagNewPassphrase
keybagQuery(common().session());
1149 keybagQuery
.inferHints(Server::process());
1150 CssmAutoData
pass(Allocator::standard(Allocator::sensitive
));
1151 CssmAutoData
oldPass(Allocator::standard(Allocator::sensitive
));
1152 SecurityAgent::Reason queryReason
= keybagQuery
.query(oldPass
, pass
);
1153 if (queryReason
== SecurityAgent::noReason
) {
1154 service_client_kb_change_secret(&context
, oldPass
.data(), (int)oldPass
.length(), pass
.data(), (int)pass
.length());
1155 } else if (queryReason
== SecurityAgent::resettingPassword
) {
1156 query
.retrievePassword(pass
);
1157 service_client_kb_reset(&context
, pass
.data(), (int)pass
.length());
1163 return reason
== SecurityAgent::noReason
;
1166 uint32_t KeychainDatabase::getInteractiveUnlockAttempts() {
1167 if (csr_check(CSR_ALLOW_APPLE_INTERNAL
)) {
1168 // Not an internal install; don't answer
1171 return interactiveUnlockAttempts
;
1177 // Same thing, but obtain a new secret somehow and set it into the common.
1179 bool KeychainDatabase::establishNewSecrets(const AccessCredentials
*creds
, SecurityAgent::Reason reason
)
1181 list
<CssmSample
> samples
;
1182 if (creds
&& creds
->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK
, samples
)) {
1183 for (list
<CssmSample
>::iterator it
= samples
.begin(); it
!= samples
.end(); it
++) {
1184 TypedList
&sample
= *it
;
1185 sample
.checkProper();
1186 switch (sample
.type()) {
1187 // interactively prompt the user
1188 case CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT
:
1190 secinfo("KCdb", "%p specified interactive passphrase", this);
1191 QueryNewPassphrase
query(*this, reason
);
1192 StSyncLock
<Mutex
, Mutex
> uisync(common().uiLock(), common());
1193 query
.inferHints(Server::process());
1194 CssmAutoData
passphrase(Allocator::standard(Allocator::sensitive
));
1195 CssmAutoData
oldPassphrase(Allocator::standard(Allocator::sensitive
));
1196 if (query(oldPassphrase
, passphrase
) == SecurityAgent::noReason
) {
1197 common().setup(NULL
, passphrase
);
1198 change_secret_on_keybag(*this, oldPassphrase
.data(), (int)oldPassphrase
.length(), passphrase
.data(), (int)passphrase
.length());
1203 // try to use an explicitly given passphrase
1204 case CSSM_SAMPLE_TYPE_PASSWORD
:
1206 secinfo("KCdb", "%p specified explicit passphrase", this);
1207 if (sample
.length() != 2)
1208 CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
);
1209 if (common().isLoginKeychain()) {
1210 CssmAutoData
oldPassphrase(Allocator::standard(Allocator::sensitive
));
1211 list
<CssmSample
> oldSamples
;
1212 creds
->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK
, oldSamples
);
1213 for (list
<CssmSample
>::iterator oit
= oldSamples
.begin(); oit
!= oldSamples
.end(); oit
++) {
1214 TypedList
&tmpList
= *oit
;
1215 tmpList
.checkProper();
1216 if (tmpList
.type() == CSSM_SAMPLE_TYPE_PASSWORD
) {
1217 if (tmpList
.length() == 2) {
1218 oldPassphrase
= tmpList
[1].data();
1222 if (!oldPassphrase
.length() && mSecret
&& mSecret
.length()) {
1223 oldPassphrase
= mSecret
;
1225 if ((oldPassphrase
.length() == sample
[1].data().length()) &&
1226 !memcmp(oldPassphrase
.data(), sample
[1].data().data(), oldPassphrase
.length()) &&
1227 oldPassphrase
.length()) {
1228 // don't change master key if the passwords are the same
1231 common().setup(NULL
, sample
[1]);
1232 change_secret_on_keybag(*this, oldPassphrase
.data(), (int)oldPassphrase
.length(), sample
[1].data().data(), (int)sample
[1].data().length());
1235 common().setup(NULL
, sample
[1]);
1239 // try to open with a given master key
1240 case CSSM_WORDID_SYMMETRIC_KEY
:
1241 case CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY
:
1242 secinfo("KCdb", "%p specified explicit master key", this);
1243 common().setup(NULL
, keyFromCreds(sample
, 3));
1245 // explicitly defeat the default action but don't try anything in particular
1246 case CSSM_WORDID_CANCELED
:
1247 secinfo("KCdb", "%p defeat default action", this);
1250 // Unknown sub-sample for acquiring new secret.
1251 // If we wanted to be fascist, we could now do
1252 // CssmError::throwMe(CSSM_ERRCODE_SAMPLE_VALUE_NOT_SUPPORTED);
1253 // But instead we try to be tolerant and continue on.
1254 // This DOES however count as an explicit attempt at specifying unlock,
1255 // so we will no longer try the default case below...
1256 secinfo("KCdb", "%p unknown sub-sample acquisition (%d) ignored",
1257 this, sample
.type());
1262 // default action -- interactive (only)
1263 QueryNewPassphrase
query(*this, reason
);
1264 StSyncLock
<Mutex
, Mutex
> uisync(common().uiLock(), common());
1265 query
.inferHints(Server::process());
1266 CssmAutoData
passphrase(Allocator::standard(Allocator::sensitive
));
1267 CssmAutoData
oldPassphrase(Allocator::standard(Allocator::sensitive
));
1268 if (query(oldPassphrase
, passphrase
) == SecurityAgent::noReason
) {
1269 common().setup(NULL
, passphrase
);
1270 change_secret_on_keybag(*this, oldPassphrase
.data(), (int)oldPassphrase
.length(), passphrase
.data(), (int)passphrase
.length());
1275 // out of options - no secret obtained
1276 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED
);
1281 // Given a (truncated) Database credentials TypedList specifying a master key,
1282 // locate the key and return a reference to it.
1284 CssmClient::Key
KeychainDatabase::keyFromCreds(const TypedList
&sample
, unsigned int requiredLength
)
1286 // decode TypedList structure (sample type; Data:CSPHandle; Data:CSSM_KEY)
1287 assert(sample
.type() == CSSM_SAMPLE_TYPE_SYMMETRIC_KEY
|| sample
.type() == CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY
);
1288 if (sample
.length() != requiredLength
1289 || sample
[1].type() != CSSM_LIST_ELEMENT_DATUM
1290 || sample
[2].type() != CSSM_LIST_ELEMENT_DATUM
1291 || (requiredLength
== 4 && sample
[3].type() != CSSM_LIST_ELEMENT_DATUM
))
1292 CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
);
1293 KeyHandle
&handle
= *sample
[1].data().interpretedAs
<KeyHandle
>(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
);
1294 // We used to be able to check the length but supporting multiple client
1295 // architectures dishes that (sizeof(CSSM_KEY) varies due to alignment and
1296 // field-size differences). The decoding in the transition layer should
1297 // serve as a sufficient garbling check anyway.
1298 if (sample
[2].data().data() == NULL
)
1299 CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
);
1300 CssmKey
&key
= *sample
[2].data().interpretedAs
<CssmKey
>();
1302 if (key
.header().cspGuid() == gGuidAppleCSPDL
) {
1303 // handleOrKey is a SecurityServer KeyHandle; ignore key argument
1304 return safer_cast
<LocalKey
&>(*Server::key(handle
));
1306 if (sample
.type() == CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY
) {
1308 Contents (see DefaultCredentials::unlockKey in libsecurity_keychain/defaultcreds.cpp)
1310 sample[0] sample type
1311 sample[1] csp handle for master or wrapping key; is really a keyhandle
1312 sample[2] masterKey [not used since securityd cannot interpret; use sample[1] handle instead]
1313 sample[3] UnlockReferralRecord data, in this case the flattened symmetric key
1316 // RefPointer<Key> Server::key(KeyHandle key)
1317 KeyHandle keyhandle
= *sample
[1].data().interpretedAs
<KeyHandle
>(CSSM_ERRCODE_INVALID_SAMPLE_VALUE
);
1318 CssmData
&flattenedKey
= sample
[3].data();
1319 RefPointer
<Key
> unwrappingKey
= Server::key(keyhandle
);
1320 Database
&db
=unwrappingKey
->database();
1322 CssmKey rawWrappedKey
;
1323 unflattenKey(flattenedKey
, rawWrappedKey
);
1325 RefPointer
<Key
> masterKey
;
1326 CssmData emptyDescriptiveData
;
1327 const AccessCredentials
*cred
= NULL
;
1328 const AclEntryPrototype
*owner
= NULL
;
1329 CSSM_KEYUSE usage
= CSSM_KEYUSE_ANY
;
1330 CSSM_KEYATTR_FLAGS attrs
= CSSM_KEYATTR_EXTRACTABLE
; //CSSM_KEYATTR_RETURN_REF |
1332 // Get default credentials for unwrappingKey (the one on the token)
1333 // Copied from Statics::Statics() in libsecurity_keychain/aclclient.cpp
1334 // Following KeyItem::getCredentials, one sees that the "operation" parameter
1335 // e.g. "CSSM_ACL_AUTHORIZATION_DECRYPT" is ignored
1336 Allocator
&alloc
= Allocator::standard();
1337 AutoCredentials
promptCred(alloc
, 3);// enable interactive prompting
1339 // promptCred: a credential permitting user prompt confirmations
1341 // a KEYCHAIN_PROMPT sample, both by itself and in a THRESHOLD
1342 // a PROMPTED_PASSWORD sample
1343 promptCred
.sample(0) = TypedList(alloc
, CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT
);
1344 promptCred
.sample(1) = TypedList(alloc
, CSSM_SAMPLE_TYPE_THRESHOLD
,
1345 new(alloc
) ListElement(TypedList(alloc
, CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT
)));
1346 promptCred
.sample(2) = TypedList(alloc
, CSSM_SAMPLE_TYPE_PROMPTED_PASSWORD
,
1347 new(alloc
) ListElement(alloc
, CssmData()));
1349 // This unwrap object is here just to provide a context
1350 CssmClient::UnwrapKey
unwrap(Server::csp(), CSSM_ALGID_NONE
); //ok to lie about csp here
1351 unwrap
.mode(CSSM_ALGMODE_NONE
);
1352 unwrap
.padding(CSSM_PADDING_PKCS1
);
1353 unwrap
.cred(promptCred
);
1354 unwrap
.add(CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT
, uint32(CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7
));
1355 Security::Context
*tmpContext
;
1356 CSSM_CC_HANDLE CCHandle
= unwrap
.handle();
1357 /*CSSM_RETURN rx = */ CSSM_GetContext (CCHandle
, (CSSM_CONTEXT_PTR
*)&tmpContext
);
1359 // OK, this is skanky but necessary. We overwrite fields in the context struct
1361 tmpContext
->ContextType
= CSSM_ALGCLASS_ASYMMETRIC
;
1362 tmpContext
->AlgorithmType
= CSSM_ALGID_RSA
;
1364 db
.unwrapKey(*tmpContext
, cred
, owner
, unwrappingKey
, NULL
, usage
, attrs
,
1365 rawWrappedKey
, masterKey
, emptyDescriptiveData
);
1367 Allocator::standard().free(rawWrappedKey
.KeyData
.Data
);
1369 return safer_cast
<LocalKey
&>(*masterKey
).key();
1371 else if (sample
.type() == CSSM_SAMPLE_TYPE_SYMMETRIC_KEY
&& sample
.length() == 4 && sample
[3].data().length() > 0) {
1373 Contents (see MasterKeyUnlockCredentials in libsecurity_cdsa_client/lib/aclclient.cpp)
1375 sample[0] sample type
1376 sample[1] 0, since we don't have a valid handle
1377 sample[2] CssmKey of the masterKey [can't immediately use since it includes a CSSM_DATA struct with pointers]
1378 sample[3] flattened symmetric master key, including the key data
1381 // Fix up key to include actual data
1382 CssmData
&flattenedKey
= sample
[3].data();
1383 unflattenKey(flattenedKey
, key
);
1385 // Check that we have a reasonable key
1386 if (key
.header().blobType() != CSSM_KEYBLOB_RAW
) {
1387 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE
);
1389 if (key
.header().keyClass() != CSSM_KEYCLASS_SESSION_KEY
) {
1390 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS
);
1393 // bring the key into the CSP and return it
1394 return CssmClient::Key(Server::csp(), key
, true);
1396 // not a KeyHandle reference; use key as a raw key
1397 if (key
.header().blobType() != CSSM_KEYBLOB_RAW
)
1398 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE
);
1399 if (key
.header().keyClass() != CSSM_KEYCLASS_SESSION_KEY
)
1400 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS
);
1401 return CssmClient::Key(Server::csp(), key
, true);
1405 void unflattenKey(const CssmData
&flatKey
, CssmKey
&rawKey
)
1407 // The format we're expecting is a CSSM_KEY followed by the actual key data:
1408 // CSSM_KEY : KEY DATA
1409 // which is approximately:
1410 // h2ni(CSSM_KEYHEADER) : 4 bytes padding : CSSM_DATA{?:?} : KEY BYTES
1412 // Note that CSSM_KEY includes a CSSM_DATA struct, which we will ignore as it has pointers.
1413 // The pointer and length will be set to whatever key data follows the CSSM_KEY in rawKey.
1415 // unflatten the raw input key naively: key header then key data
1416 // We also convert it back to host byte order
1417 // A CSSM_KEY is a CSSM_KEYHEADER followed by a CSSM_DATA
1419 // Now copy: header, then key struct, then key data
1420 memcpy(&rawKey
.KeyHeader
, flatKey
.Data
, sizeof(CSSM_KEYHEADER
));
1421 memcpy(&rawKey
.KeyData
, flatKey
.Data
+ sizeof(CSSM_KEYHEADER
), sizeof(CSSM_DATA
));
1422 size_t keyDataLength
= flatKey
.length() - sizeof(CSSM_KEY
);
1423 rawKey
.KeyData
.Data
= Allocator::standard().malloc
<uint8
>(keyDataLength
);
1424 rawKey
.KeyData
.Length
= keyDataLength
;
1425 memcpy(rawKey
.KeyData
.Data
, flatKey
.Data
+ sizeof(CSSM_KEY
), keyDataLength
);
1426 Security::n2hi(rawKey
.KeyHeader
); // convert it to host byte order
1431 // Verify a putative database passphrase.
1432 // If the database is already unlocked, just check the passphrase.
1433 // Otherwise, unlock with that passphrase and report success.
1434 // Caller must hold the common lock.
1436 bool KeychainDatabase::validatePassphrase(const CssmData
&passphrase
) const
1438 if (common().hasMaster()) {
1439 // verify against known secret
1440 return common().validatePassphrase(passphrase
);
1442 // no master secret - perform "blind" unlock to avoid actual unlock
1444 DatabaseCryptoCore test
;
1445 test
.setup(mBlob
, passphrase
);
1446 test
.decodeCore(mBlob
, NULL
);
1456 // Lock this database
1458 void KeychainDatabase::lockDb()
1465 // Given a Key for this database, encode it into a blob and return it.
1467 KeyBlob
*KeychainDatabase::encodeKey(const CssmKey
&key
, const CssmData
&pubAcl
, const CssmData
&privAcl
)
1469 bool inTheClear
= false;
1470 if((key
.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY
) &&
1471 !(key
.attribute(CSSM_KEYATTR_PUBLIC_KEY_ENCRYPT
))) {
1474 StLock
<Mutex
> _(common());
1476 makeUnlocked(false);
1478 // tell the cryptocore to form the key blob
1479 return common().encodeKeyCore(key
, pubAcl
, privAcl
, inTheClear
);
1484 // Given a "blobbed" key for this database, decode it into its real
1485 // key object and (re)populate its ACL.
1487 void KeychainDatabase::decodeKey(KeyBlob
*blob
, CssmKey
&key
, void * &pubAcl
, void * &privAcl
)
1489 StLock
<Mutex
> _(common());
1491 if(!blob
->isClearText())
1492 makeUnlocked(false); // we need our keys
1494 common().decodeKeyCore(blob
, key
, pubAcl
, privAcl
);
1495 // memory protocol: pubAcl points into blob; privAcl was allocated
1501 // Given a KeychainKey (that implicitly belongs to another keychain),
1502 // return it encoded using this keychain's operational secrets.
1504 KeyBlob
*KeychainDatabase::recodeKey(KeychainKey
&oldKey
)
1506 if (mRecodingSource
!= &oldKey
.referent
<KeychainDatabase
>()) {
1507 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
1510 // To protect this operation, we need to take the mutex for both our common and the remote key's common in some defined order.
1511 // Grab the common being cloned (oldKey's) first, and then the common receiving the recoding (ours).
1512 StLock
<Mutex
> _ (oldKey
.referent
<KeychainDatabase
>().common());
1513 StLock
<Mutex
> __(common());
1515 oldKey
.instantiateAcl(); // make sure key is decoded
1516 CssmData publicAcl
, privateAcl
;
1517 oldKey
.exportBlob(publicAcl
, privateAcl
);
1518 // NB: blob's memory belongs to caller, not the common
1521 * Make sure the new key is in the same cleartext/encrypted state.
1523 bool inTheClear
= false;
1524 assert(oldKey
.blob());
1525 if(oldKey
.blob() && oldKey
.blob()->isClearText()) {
1529 KeyBlob
*blob
= common().encodeKeyCore(oldKey
.cssmKey(), publicAcl
, privateAcl
, inTheClear
);
1530 oldKey
.acl().allocator
.free(publicAcl
);
1531 oldKey
.acl().allocator
.free(privateAcl
);
1537 // Modify database parameters
1539 void KeychainDatabase::setParameters(const DBParameters
¶ms
)
1541 StLock
<Mutex
> _(common());
1542 makeUnlocked(false);
1543 common().mParams
= params
;
1544 common().invalidateBlob(); // invalidate old blobs
1545 activity(); // (also resets the timeout timer)
1546 secinfo("KCdb", "%p common %p(%s) set params=(%u,%u)",
1547 this, &common(), dbName(), params
.idleTimeout
, params
.lockOnSleep
);
1552 // Retrieve database parameters
1554 void KeychainDatabase::getParameters(DBParameters
¶ms
)
1556 StLock
<Mutex
> _(common());
1557 makeUnlocked(false);
1558 params
= common().mParams
;
1559 //activity(); // getting parameters does not reset the idle timer
1564 // RIGHT NOW, database ACLs are attached to the database.
1565 // This will soon move upstairs.
1567 SecurityServerAcl
&KeychainDatabase::acl()
1574 // Intercept ACL change requests and reset blob validity
1576 void KeychainDatabase::instantiateAcl()
1578 StLock
<Mutex
> _(common());
1579 makeUnlocked(false);
1582 void KeychainDatabase::changedAcl()
1584 StLock
<Mutex
> _(common());
1590 // Check an incoming DbBlob for basic viability
1592 void KeychainDatabase::validateBlob(const DbBlob
*blob
)
1594 // perform basic validation on the blob
1596 blob
->validate(CSSMERR_APPLEDL_INVALID_DATABASE_BLOB
);
1597 switch (blob
->version()) {
1598 #if defined(COMPAT_OSX_10_0)
1599 case DbBlob::version_MacOS_10_0
:
1602 case DbBlob::version_MacOS_10_1
:
1604 case DbBlob::version_partition
:
1607 CssmError::throwMe(CSSMERR_APPLEDL_INCOMPATIBLE_DATABASE_BLOB
);
1612 // Check if this database is currently recoding
1614 bool KeychainDatabase::isRecoding()
1616 secnotice("integrity", "recoding source: %p", mRecodingSource
.get());
1617 return (mRecodingSource
.get() != NULL
|| mRecoded
);
1621 // Mark ourselves as no longer recoding
1623 void KeychainDatabase::recodeFinished()
1625 secnotice("integrity", "recoding finished");
1626 mRecodingSource
= NULL
;
1632 // Debugging support
1634 #if defined(DEBUGDUMP)
1636 void KeychainDbCommon::dumpNode()
1638 PerSession::dumpNode();
1639 uint32 sig
; memcpy(&sig
, &mIdentifier
.signature(), sizeof(sig
));
1640 Debug::dump(" %s[%8.8x]", mIdentifier
.dbName(), sig
);
1642 Debug::dump(" locked");
1644 time_t whenTime
= time_t(when());
1645 Debug::dump(" unlocked(%24.24s/%.2g)", ctime(&whenTime
),
1646 (when() - Time::now()).seconds());
1648 Debug::dump(" params=(%u,%u)", mParams
.idleTimeout
, mParams
.lockOnSleep
);
1651 void KeychainDatabase::dumpNode()
1653 PerProcess::dumpNode();
1654 Debug::dump(" %s vers=%u",
1655 mValidData
? " data" : " nodata", version
);
1657 uint32 sig
; memcpy(&sig
, &mBlob
->randomSignature
, sizeof(sig
));
1658 Debug::dump(" blob=%p[%8.8x]", mBlob
, sig
);
1660 Debug::dump(" noblob");
1668 // DbCommon basic features
1670 KeychainDbCommon::KeychainDbCommon(Session
&ssn
, const DbIdentifier
&id
, uint32 requestedVersion
)
1671 : LocalDbCommon(ssn
), DatabaseCryptoCore(requestedVersion
), sequence(0), version(1), mIdentifier(id
),
1672 mIsLocked(true), mValidParams(false), mLoginKeychain(false)
1674 // match existing DbGlobal or create a new one
1676 Server
&server
= Server::active();
1677 StLock
<Mutex
> _(server
);
1678 if (KeychainDbGlobal
*dbglobal
=
1679 server
.findFirst
<KeychainDbGlobal
, const DbIdentifier
&>(&KeychainDbGlobal::identifier
, identifier())) {
1681 secinfo("KCdb", "%p linking to existing DbGlobal %p", this, dbglobal
);
1683 // DbGlobal not present; make a new one
1684 parent(*new KeychainDbGlobal(identifier()));
1685 secinfo("KCdb", "%p linking to new DbGlobal %p", this, &global());
1688 // link lifetime to the Session
1689 session().addReference(*this);
1691 if (strcasestr(id
.dbName(), "login.keychain") != NULL
) {
1692 mLoginKeychain
= true;
1697 void KeychainDbCommon::initializeKeybag() {
1698 if (mLoginKeychain
&& !session().keybagGetState(session_keybag_loaded
)) {
1699 service_context_t context
= session().get_current_service_context();
1700 if (service_client_kb_load(&context
) == 0) {
1701 session().keybagSetState(session_keybag_loaded
);
1706 KeychainDbCommon::KeychainDbCommon(Session
&ssn
, const DbIdentifier
&id
, KeychainDbCommon
& toClone
)
1707 : LocalDbCommon(ssn
), DatabaseCryptoCore(toClone
.mBlobVersion
), sequence(toClone
.sequence
), mParams(toClone
.mParams
), version(toClone
.version
),
1708 mIdentifier(id
), mIsLocked(toClone
.mIsLocked
), mValidParams(toClone
.mValidParams
), mLoginKeychain(toClone
.mLoginKeychain
)
1713 Server
&server
= Server::active();
1714 StLock
<Mutex
> _(server
);
1715 if (KeychainDbGlobal
*dbglobal
=
1716 server
.findFirst
<KeychainDbGlobal
, const DbIdentifier
&>(&KeychainDbGlobal::identifier
, identifier())) {
1718 secinfo("KCdb", "%p linking to existing DbGlobal %p", this, dbglobal
);
1720 // DbGlobal not present; make a new one
1721 parent(*new KeychainDbGlobal(identifier()));
1722 secinfo("KCdb", "%p linking to new DbGlobal %p", this, &global());
1724 session().addReference(*this);
1728 KeychainDbCommon::~KeychainDbCommon()
1730 secinfo("KCdb", "releasing keychain %p %s", this, (char*)this->dbName());
1732 // explicitly unschedule ourselves
1733 Server::active().clearTimer(this);
1734 if (mLoginKeychain
) {
1735 session().keybagClearState(session_keybag_unlocked
);
1737 // remove ourselves from mCommonSet
1741 void KeychainDbCommon::cloneFrom(KeychainDbCommon
& toClone
, uint32 requestedVersion
) {
1742 // don't clone the mIdentifier
1743 sequence
= toClone
.sequence
;
1744 mParams
= toClone
.mParams
;
1745 version
= toClone
.version
;
1746 mIsLocked
= toClone
.mIsLocked
;
1747 mValidParams
= toClone
.mValidParams
;
1748 mLoginKeychain
= toClone
.mLoginKeychain
;
1750 DatabaseCryptoCore::initializeFrom(toClone
, requestedVersion
);
1753 void KeychainDbCommon::kill()
1755 StReadWriteLock
_(mRWCommonLock
, StReadWriteLock::Write
);
1756 mCommonSet
.erase(this);
1759 KeychainDbGlobal
&KeychainDbCommon::global() const
1761 return parent
<KeychainDbGlobal
>();
1765 void KeychainDbCommon::select()
1768 void KeychainDbCommon::unselect()
1773 void KeychainDbCommon::makeNewSecrets()
1775 // we already have a master key (right?)
1776 assert(hasMaster());
1778 // tell crypto core to generate the use keys
1779 DatabaseCryptoCore::generateNewSecrets();
1781 // we're now officially "unlocked"; set the timer
1787 // All unlocking activity ultimately funnels through this method.
1788 // This unlocks a DbCommon using the secrets setup in its crypto core
1789 // component, and performs all the housekeeping needed to represent
1790 // the state change.
1791 // Returns true if unlock was successful, false if it failed due to
1792 // invalid/insufficient secrets. Throws on other errors.
1794 bool KeychainDbCommon::unlockDb(DbBlob
*blob
, void **privateAclBlob
)
1797 // Tell the cryptocore to (try to) decode itself. This will fail
1798 // in an astonishing variety of ways if the passphrase is wrong.
1799 assert(hasMaster());
1800 decodeCore(blob
, privateAclBlob
);
1801 secinfo("KCdb", "%p unlock successful", this);
1803 secinfo("KCdb", "%p unlock failed", this);
1807 // get the database parameters only if we haven't got them yet
1808 if (!mValidParams
) {
1809 mParams
= blob
->params
;
1810 n2hi(mParams
.idleTimeout
);
1811 mValidParams
= true; // sticky
1814 bool isLocked
= mIsLocked
;
1816 setUnlocked(); // mark unlocked
1819 // broadcast unlock notification, but only if we were previously locked
1820 notify(kNotificationEventUnlocked
);
1821 secinfo("KCdb", "unlocking keychain %p %s", this, (char*)this->dbName());
1826 void KeychainDbCommon::setUnlocked()
1828 session().addReference(*this); // active/held
1829 mIsLocked
= false; // mark unlocked
1830 activity(); // set timeout timer
1834 void KeychainDbCommon::lockDb()
1838 StLock
<Mutex
> _(*this);
1840 DatabaseCryptoCore::invalidate();
1841 notify(kNotificationEventLocked
);
1842 secinfo("KCdb", "locking keychain %p %s", this, (char*)this->dbName());
1843 Server::active().clearTimer(this);
1845 mIsLocked
= true; // mark locked
1848 // this call may destroy us if we have no databases anymore
1849 session().removeReference(*this);
1855 DbBlob
*KeychainDbCommon::encode(KeychainDatabase
&db
)
1857 assert(!isLocked()); // must have been unlocked by caller
1859 // export database ACL to blob form
1860 CssmData pubAcl
, privAcl
;
1861 db
.acl().exportBlob(pubAcl
, privAcl
);
1863 // tell the cryptocore to form the blob
1865 form
.randomSignature
= identifier();
1866 form
.sequence
= sequence
;
1867 form
.params
= mParams
;
1868 h2ni(form
.params
.idleTimeout
);
1870 assert(hasMaster());
1871 DbBlob
*blob
= encodeCore(form
, pubAcl
, privAcl
);
1874 db
.acl().allocator
.free(pubAcl
);
1875 db
.acl().allocator
.free(privAcl
);
1881 // Perform deferred lock processing for a database.
1883 void KeychainDbCommon::action()
1885 secinfo("KCdb", "common %s(%p) locked by timer", dbName(), this);
1889 void KeychainDbCommon::activity()
1892 secinfo("KCdb", "setting DbCommon %p timer to %d",
1893 this, int(mParams
.idleTimeout
));
1894 Server::active().setTimer(this, Time::Interval(int(mParams
.idleTimeout
)));
1898 void KeychainDbCommon::sleepProcessing()
1900 secinfo("KCdb", "common %s(%p) sleep-lock processing", dbName(), this);
1901 if (mParams
.lockOnSleep
&& !isDefaultSystemKeychain()) {
1902 StLock
<Mutex
> _(*this);
1907 void KeychainDbCommon::lockProcessing()
1914 // We consider a keychain to belong to the system domain if it resides
1915 // in /Library/Keychains. That's not exactly fool-proof, but we don't
1916 // currently have any internal markers to interrogate.
1918 bool KeychainDbCommon::belongsToSystem() const
1920 if (const char *name
= this->dbName())
1921 return !strncmp(name
, "/Library/Keychains/", 19);
1925 bool KeychainDbCommon::isDefaultSystemKeychain() const
1927 // /Library/Keychains/System.keychain (34)
1928 if (const char *name
= this->dbName())
1929 return !strncmp(name
, "/Library/Keychains/System.keychain", 34);
1934 // Keychain global objects
1936 KeychainDbGlobal::KeychainDbGlobal(const DbIdentifier
&id
)
1941 KeychainDbGlobal::~KeychainDbGlobal()
1943 secinfo("KCdb", "DbGlobal %p destroyed", this);