]> git.saurik.com Git - apple/securityd.git/blob - src/kcdatabase.cpp
securityd-55199.0.1.tar.gz
[apple/securityd.git] / src / kcdatabase.cpp
1 /*
2 * Copyright (c) 2000-2008 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 #include "kcdatabase.h"
41 #include "agentquery.h"
42 #include "kckey.h"
43 #include "server.h"
44 #include "session.h"
45 #include "notifications.h"
46 #include <vector> // @@@ 4003540 workaround
47 #include <security_agent_client/agentclient.h>
48 #include <security_cdsa_utilities/acl_any.h> // for default owner ACLs
49 #include <security_cdsa_utilities/cssmendian.h>
50 #include <security_cdsa_client/wrapkey.h>
51 #include <security_cdsa_client/genkey.h>
52 #include <security_cdsa_client/signclient.h>
53 #include <security_cdsa_client/cryptoclient.h>
54 #include <security_cdsa_client/macclient.h>
55 #include <securityd_client/dictionary.h>
56 #include <security_utilities/endian.h>
57 #include "securityd_service/securityd_service/securityd_service_client.h"
58 #include <AssertMacros.h>
59 #include <syslog.h>
60
61 void unflattenKey(const CssmData &flatKey, CssmKey &rawKey); //>> make static method on KeychainDatabase
62
63 static int
64 unlock_keybag(KeychainDbCommon & dbCommon, const void * secret, int secret_len)
65 {
66 int rc = -1;
67
68 if (!dbCommon.isLoginKeychain()) return 0;
69
70 service_context_t context = dbCommon.session().get_current_service_context();
71
72 // try to unlock first if not found then load/create or unlock
73 // loading should happen when the kb common object is created
74 // if it doesn't exist yet then the unlock will fail and we'll create everything
75 rc = service_client_kb_unlock(&context, secret, secret_len);
76 if (rc == KB_BagNotLoaded) {
77 if (service_client_kb_load(&context) == KB_BagNotFound) {
78 rc = service_client_kb_create(&context, secret, secret_len);
79 } else {
80 rc = service_client_kb_unlock(&context, secret, secret_len);
81 }
82 }
83
84 if (rc != 0) { // if we just upgraded make sure we swap the encryption key to the password
85 if (!dbCommon.session().keybagGetState(session_keybag_check_master_key)) {
86 CssmAutoData encKey(Allocator::standard(Allocator::sensitive));
87 dbCommon.get_encryption_key(encKey);
88 if ((rc = service_client_kb_unlock(&context, encKey.data(), (int)encKey.length())) == 0) {
89 rc = service_client_kb_change_secret(&context, encKey.data(), (int)encKey.length(), secret, secret_len);
90 }
91
92 if (rc != 0) { // if a login.keychain password exists but doesnt on the keybag update it
93 bool no_pin = false;
94 if ((secret_len > 0) && service_client_kb_is_locked(&context, NULL, &no_pin) == 0) {
95 if (no_pin) {
96 syslog(LOG_ERR, "Updating iCloud keychain passphrase for uid %d", dbCommon.session().originatorUid());
97 service_client_kb_change_secret(&context, NULL, 0, secret, secret_len);
98 }
99 }
100 }
101 } // session_keybag_check_master_key
102 }
103
104 if (rc == 0) {
105 dbCommon.session().keybagSetState(session_keybag_unlocked|session_keybag_loaded|session_keybag_check_master_key);
106 } else {
107 syslog(LOG_ERR, "Failed to unlock iCloud keychain for uid %d", dbCommon.session().originatorUid());
108 }
109
110 return rc;
111 }
112
113 static void
114 change_secret_on_keybag(KeychainDbCommon & dbCommon, const void * secret, int secret_len, const void * new_secret, int new_secret_len)
115 {
116 if (!dbCommon.isLoginKeychain()) return;
117
118 service_context_t context = dbCommon.session().get_current_service_context();
119
120 // if a login.keychain doesn't exist yet it comes into securityd as a create then change_secret
121 // we need to create the keybag in this case if it doesn't exist
122 if (service_client_kb_change_secret(&context, secret, secret_len, new_secret, new_secret_len) == KB_BagNotLoaded) {
123 if (service_client_kb_load(&context) == KB_BagNotFound) {
124 service_client_kb_create(&context, new_secret, new_secret_len);
125 }
126 }
127 }
128
129 //
130 // Create a Database object from initial parameters (create operation)
131 //
132 KeychainDatabase::KeychainDatabase(const DLDbIdentifier &id, const DBParameters &params, Process &proc,
133 const AccessCredentials *cred, const AclEntryPrototype *owner)
134 : LocalDatabase(proc), mValidData(false), mSecret(Allocator::standard(Allocator::sensitive)), mSaveSecret(false), version(0), mBlob(NULL)
135 {
136 // save a copy of the credentials for later access control
137 mCred = DataWalkers::copy(cred, Allocator::standard());
138
139 // create a new random signature to complete the DLDbIdentifier
140 DbBlob::Signature newSig;
141 Server::active().random(newSig.bytes);
142 DbIdentifier ident(id, newSig);
143
144 // create common block and initialize
145 RefPointer<KeychainDbCommon> newCommon = new KeychainDbCommon(proc.session(), ident);
146 StLock<Mutex> _(*newCommon);
147 parent(*newCommon);
148 // new common is now visible (in ident-map) but we hold its lock
149
150 // establish the new master secret
151 establishNewSecrets(cred, SecurityAgent::newDatabase);
152
153 // set initial database parameters
154 common().mParams = params;
155
156 // the common is "unlocked" now
157 common().makeNewSecrets();
158
159 // establish initial ACL
160 if (owner)
161 acl().cssmSetInitial(*owner);
162 else
163 acl().cssmSetInitial(new AnyAclSubject());
164 mValidData = true;
165
166 // for now, create the blob immediately
167 encode();
168
169 proc.addReference(*this);
170
171 // this new keychain is unlocked; make it so
172 activity();
173
174 SECURITYD_KEYCHAIN_CREATE(&common(), (char*)this->dbName(), this);
175 }
176
177
178 //
179 // Create a Database object from a database blob (decoding)
180 //
181 KeychainDatabase::KeychainDatabase(const DLDbIdentifier &id, const DbBlob *blob, Process &proc,
182 const AccessCredentials *cred)
183 : LocalDatabase(proc), mValidData(false), mSecret(Allocator::standard(Allocator::sensitive)), mSaveSecret(false), version(0), mBlob(NULL)
184 {
185 validateBlob(blob);
186
187 // save a copy of the credentials for later access control
188 mCred = DataWalkers::copy(cred, Allocator::standard());
189 mBlob = blob->copy();
190
191 // check to see if we already know about this database
192 DbIdentifier ident(id, blob->randomSignature);
193 Session &session = process().session();
194 StLock<Mutex> _(session);
195 if (KeychainDbCommon *dbcom =
196 session.findFirst<KeychainDbCommon, const DbIdentifier &>(&KeychainDbCommon::identifier, ident)) {
197 parent(*dbcom);
198 //@@@ arbitrate sequence number here, perhaps update common().mParams
199 SECURITYD_KEYCHAIN_JOIN(&common(), (char*)this->dbName(), this);
200 } else {
201 // DbCommon not present; make a new one
202 parent(*new KeychainDbCommon(proc.session(), ident));
203 common().mParams = blob->params;
204 SECURITYD_KEYCHAIN_MAKE(&common(), (char*)this->dbName(), this);
205 // this DbCommon is locked; no timer or reference setting
206 }
207 proc.addReference(*this);
208 }
209
210
211 // recode/clone:
212 //
213 // Special-purpose constructor for keychain synchronization. Copies an
214 // existing keychain but uses the operational keys from secretsBlob. The
215 // new KeychainDatabase will silently replace the existing KeychainDatabase
216 // as soon as the client declares that re-encoding of all keychain items is
217 // finished. This is a little perilous since it allows a client to dictate
218 // securityd state, but we try to ensure that only the client that started
219 // the re-encoding can declare it done.
220 //
221 KeychainDatabase::KeychainDatabase(KeychainDatabase &src, Process &proc, DbHandle dbToClone)
222 : LocalDatabase(proc), mValidData(false), mSecret(Allocator::standard(Allocator::sensitive)), mSaveSecret(false), version(0), mBlob(NULL)
223 {
224 mCred = DataWalkers::copy(src.mCred, Allocator::standard());
225
226 // Give this KeychainDatabase a temporary name
227 std::string newDbName = std::string("////") + std::string(src.identifier().dbName());
228 DLDbIdentifier newDLDbIdent(src.identifier().dlDbIdentifier().ssuid(), newDbName.c_str(), src.identifier().dlDbIdentifier().dbLocation());
229 DbIdentifier ident(newDLDbIdent, src.identifier());
230
231 // create common block and initialize
232 RefPointer<KeychainDbCommon> newCommon = new KeychainDbCommon(proc.session(), ident);
233 StLock<Mutex> _(*newCommon);
234 parent(*newCommon);
235
236 // set initial database parameters from the source keychain
237 common().mParams = src.common().mParams;
238
239 // establish the source keychain's master secret as ours
240 // @@@ NB: this is a v. 0.1 assumption. We *should* trigger new UI
241 // that offers the user the option of using the existing password
242 // or choosing a new one. That would require a new
243 // SecurityAgentQuery type, new UI, and--possibly--modifications to
244 // ensure that the new password is available here to generate the
245 // new master secret.
246 src.unlockDb(); // precaution for masterKey()
247 common().setup(src.blob(), src.common().masterKey());
248
249 // import the operational secrets
250 RefPointer<KeychainDatabase> srcKC = Server::keychain(dbToClone);
251 common().importSecrets(srcKC->common());
252
253 // import source keychain's ACL
254 CssmData pubAcl, privAcl;
255 src.acl().exportBlob(pubAcl, privAcl);
256 importBlob(pubAcl.data(), privAcl.data());
257 src.acl().allocator.free(pubAcl);
258 src.acl().allocator.free(privAcl);
259
260 // indicate that this keychain should be allowed to do some otherwise
261 // risky things required for copying, like re-encoding keys
262 mRecodingSource = &src;
263
264 common().setUnlocked();
265 mValidData = true;
266
267 encode();
268
269 proc.addReference(*this);
270 secdebug("SSdb", "database %s(%p) created as copy, common at %p",
271 common().dbName(), this, &common());
272 }
273
274 //
275 // Destroy a Database
276 //
277 KeychainDatabase::~KeychainDatabase()
278 {
279 secdebug("KCdb", "deleting database %s(%p) common %p",
280 common().dbName(), this, &common());
281 Allocator::standard().free(mCred);
282 Allocator::standard().free(mBlob);
283 }
284
285
286 //
287 // Basic Database virtual implementations
288 //
289 KeychainDbCommon &KeychainDatabase::common() const
290 {
291 return parent<KeychainDbCommon>();
292 }
293
294 const char *KeychainDatabase::dbName() const
295 {
296 return common().dbName();
297 }
298
299 bool KeychainDatabase::transient() const
300 {
301 return false; // has permanent store
302 }
303
304 AclKind KeychainDatabase::aclKind() const
305 {
306 return dbAcl;
307 }
308
309 Database *KeychainDatabase::relatedDatabase()
310 {
311 return this;
312 }
313
314
315 static inline KeychainKey &myKey(Key *key)
316 {
317 return *safe_cast<KeychainKey *>(key);
318 }
319
320
321 //
322 // (Re-)Authenticate the database. This changes the stored credentials.
323 //
324 void KeychainDatabase::authenticate(CSSM_DB_ACCESS_TYPE mode,
325 const AccessCredentials *cred)
326 {
327 StLock<Mutex> _(common());
328
329 // the (Apple specific) RESET bit means "lock the database now"
330 switch (mode) {
331 case CSSM_DB_ACCESS_RESET:
332 secdebug("KCdb", "%p ACCESS_RESET triggers keychain lock", this);
333 common().lockDb();
334 break;
335 default:
336 // store the new credentials for future use
337 secdebug("KCdb", "%p authenticate stores new database credentials", this);
338 AccessCredentials *newCred = DataWalkers::copy(cred, Allocator::standard());
339 Allocator::standard().free(mCred);
340 mCred = newCred;
341 }
342 }
343
344
345 //
346 // Make a new KeychainKey.
347 // If PERMANENT is off, make a temporary key instead.
348 // The db argument allows you to create for another KeychainDatabase (only);
349 // it defaults to ourselves.
350 //
351 RefPointer<Key> KeychainDatabase::makeKey(Database &db, const CssmKey &newKey,
352 uint32 moreAttributes, const AclEntryPrototype *owner)
353 {
354
355 if (moreAttributes & CSSM_KEYATTR_PERMANENT)
356 return new KeychainKey(db, newKey, moreAttributes, owner);
357 else
358 return process().makeTemporaryKey(newKey, moreAttributes, owner);
359 }
360
361 RefPointer<Key> KeychainDatabase::makeKey(const CssmKey &newKey,
362 uint32 moreAttributes, const AclEntryPrototype *owner)
363 {
364 return makeKey(*this, newKey, moreAttributes, owner);
365 }
366
367
368 //
369 // Return the database blob, recalculating it as needed.
370 //
371 DbBlob *KeychainDatabase::blob()
372 {
373 StLock<Mutex> _(common());
374 if (!validBlob()) {
375 makeUnlocked(); // unlock to get master secret
376 encode(); // (re)encode blob if needed
377 }
378 activity(); // reset timeout
379 assert(validBlob()); // better have a valid blob now...
380 return mBlob;
381 }
382
383
384 //
385 // Encode the current database as a blob.
386 // Note that this returns memory we own and keep.
387 // Caller must hold common lock.
388 //
389 void KeychainDatabase::encode()
390 {
391 DbBlob *blob = common().encode(*this);
392 Allocator::standard().free(mBlob);
393 mBlob = blob;
394 version = common().version;
395 secdebug("KCdb", "encoded database %p common %p(%s) version %u params=(%u,%u)",
396 this, &common(), dbName(), version,
397 common().mParams.idleTimeout, common().mParams.lockOnSleep);
398 }
399
400
401 //
402 // Change the passphrase on a database
403 //
404 void KeychainDatabase::changePassphrase(const AccessCredentials *cred)
405 {
406 // get and hold the common lock (don't let other threads break in here)
407 StLock<Mutex> _(common());
408
409 // establish OLD secret - i.e. unlock the database
410 //@@@ do we want to leave the final lock state alone?
411 if (common().isLoginKeychain()) mSaveSecret = true;
412 makeUnlocked(cred);
413
414 // establish NEW secret
415 establishNewSecrets(cred, SecurityAgent::changePassphrase);
416 if (mSecret) { mSecret.reset(); }
417 mSaveSecret = false;
418 common().invalidateBlob(); // blob state changed
419 secdebug("KCdb", "Database %s(%p) master secret changed", common().dbName(), this);
420 encode(); // force rebuild of local blob
421
422 // send out a notification
423 notify(kNotificationEventPassphraseChanged);
424
425 // I guess this counts as an activity
426 activity();
427 }
428
429 //
430 // Second stage of keychain synchronization: overwrite the original keychain's
431 // (this KeychainDatabase's) operational secrets
432 //
433 void KeychainDatabase::commitSecretsForSync(KeychainDatabase &cloneDb)
434 {
435 StLock<Mutex> _(common());
436
437 // try to detect spoofing
438 if (cloneDb.mRecodingSource != this)
439 CssmError::throwMe(CSSM_ERRCODE_INVALID_DB_HANDLE);
440
441 // in case we autolocked since starting the sync
442 makeUnlocked(); // call this because we already own the lock
443 cloneDb.unlockDb(); // we may not own the lock here, so calling unlockDb will lock the cloneDb's common lock
444
445 // Decode all keys whose handles refer to this on-disk keychain so that
446 // if the holding client commits the key back to disk, it's encoded with
447 // the new operational secrets. The recoding client *must* hold a write
448 // lock for the on-disk keychain from the moment it starts recoding key
449 // items until after this call.
450 //
451 // @@@ This specific implementation is a workaround for 4003540.
452 std::vector<U32HandleObject::Handle> handleList;
453 U32HandleObject::findAllRefs<KeychainKey>(handleList);
454 size_t count = handleList.size();
455 if (count > 0) {
456 for (unsigned int n = 0; n < count; ++n) {
457 RefPointer<KeychainKey> kckey =
458 U32HandleObject::findRefAndLock<KeychainKey>(handleList[n], CSSMERR_CSP_INVALID_KEY_REFERENCE);
459 StLock<Mutex> _(*kckey/*, true*/);
460 if (kckey->database().global().identifier() == identifier()) {
461 kckey->key(); // force decode
462 kckey->invalidateBlob();
463 secdebug("kcrecode", "changed extant key %p (proc %d)",
464 &*kckey, kckey->process().pid());
465 }
466 }
467 }
468
469 // it is now safe to replace the old op secrets
470 common().importSecrets(cloneDb.common());
471 common().invalidateBlob();
472 }
473
474
475 //
476 // Extract the database master key as a proper Key object.
477 //
478 RefPointer<Key> KeychainDatabase::extractMasterKey(Database &db,
479 const AccessCredentials *cred, const AclEntryPrototype *owner,
480 uint32 usage, uint32 attrs)
481 {
482 // get and hold common lock
483 StLock<Mutex> _(common());
484
485 // force lock to require re-validation of credentials
486 lockDb();
487
488 // unlock to establish master secret
489 makeUnlocked();
490
491 // extract the raw cryptographic key
492 CssmClient::WrapKey wrap(Server::csp(), CSSM_ALGID_NONE);
493 CssmKey key;
494 wrap(common().masterKey(), key);
495
496 // make the key object and return it
497 return makeKey(db, key, attrs & LocalKey::managedAttributes, owner);
498 }
499
500
501 //
502 // Unlock this database (if needed) by obtaining the master secret in some
503 // suitable way and then proceeding to unlock with it.
504 // Does absolutely nothing if the database is already unlocked.
505 // The makeUnlocked forms are identical except the assume the caller already
506 // holds the common lock.
507 //
508 void KeychainDatabase::unlockDb()
509 {
510 StLock<Mutex> _(common());
511 makeUnlocked();
512 }
513
514 void KeychainDatabase::makeUnlocked()
515 {
516 return makeUnlocked(mCred);
517 }
518
519 void KeychainDatabase::makeUnlocked(const AccessCredentials *cred)
520 {
521 if (isLocked()) {
522 secdebug("KCdb", "%p(%p) unlocking for makeUnlocked()", this, &common());
523 assert(mBlob || (mValidData && common().hasMaster()));
524 establishOldSecrets(cred);
525 common().setUnlocked(); // mark unlocked
526 } else if (common().isLoginKeychain()) {
527 bool locked = false;
528 service_context_t context = common().session().get_current_service_context();
529 if ((service_client_kb_is_locked(&context, &locked, NULL) == 0) && locked) {
530 StSyncLock<Mutex, Mutex> uisync(common().uiLock(), common());
531 QueryKeybagPassphrase keybagQuery(common().session(), 3);
532 keybagQuery.inferHints(Server::process());
533 if (keybagQuery.query() != SecurityAgent::noReason) {
534 syslog(LOG_NOTICE, "failed to unlock iCloud keychain");
535 }
536 }
537 }
538 if (!mValidData) { // need to decode to get our ACLs, master secret available
539 secdebug("KCdb", "%p(%p) is unlocked; decoding for makeUnlocked()", this, &common());
540 if (!decode())
541 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
542 }
543 assert(!isLocked());
544 assert(mValidData);
545 }
546
547 //
548 // Invoke the securityd_service to retrieve the keychain master
549 // key from the AppleFDEKeyStore.
550 //
551 void KeychainDatabase::stashDbCheck()
552 {
553 CssmAutoData masterKey(Allocator::standard(Allocator::sensitive));
554 CssmAutoData encKey(Allocator::standard(Allocator::sensitive));
555
556 // Fetch the key
557 int rc = 0;
558 void * stash_key = NULL;
559 int stash_key_len = 0;
560 service_context_t context = common().session().get_current_service_context();
561 rc = service_client_stash_get_key(&context, &stash_key, &stash_key_len);
562 if (rc == 0) {
563 if (stash_key) {
564 masterKey.copy(CssmData((void *)stash_key,stash_key_len));
565 memset(stash_key, 0, stash_key_len);
566 free(stash_key);
567 }
568 } else {
569 CssmError::throwMe(rc);
570 }
571
572 {
573 StLock<Mutex> _(common());
574
575 // Now establish it as the keychain master key
576 CssmClient::Key key(Server::csp(), masterKey.get());
577 CssmKey::Header &hdr = key.header();
578 hdr.keyClass(CSSM_KEYCLASS_SESSION_KEY);
579 hdr.algorithm(CSSM_ALGID_3DES_3KEY_EDE);
580 hdr.usage(CSSM_KEYUSE_ANY);
581 hdr.blobType(CSSM_KEYBLOB_RAW);
582 hdr.blobFormat(CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING);
583 common().setup(mBlob, key);
584
585 if (!decode())
586 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
587
588 common().get_encryption_key(encKey);
589 }
590
591 // when upgrading from pre-10.9 create a keybag if it doesn't exist with the encryption key
592 // only do this after we have verified the master key unlocks the login.keychain
593 if (service_client_kb_load(&context) == KB_BagNotFound) {
594 service_client_kb_create(&context, encKey.data(), (int)encKey.length());
595 }
596 }
597
598 //
599 // Get the keychain master key and invoke the securityd_service
600 // to stash it in the AppleFDEKeyStore ready for commit to the
601 // NVRAM blob.
602 //
603 void KeychainDatabase::stashDb()
604 {
605 CssmAutoData data(Allocator::standard(Allocator::sensitive));
606
607 {
608 StLock<Mutex> _(common());
609
610 if (!common().isValid()) {
611 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
612 }
613
614 CssmKey key = common().masterKey();
615 data.copy(key.keyData());
616 }
617
618 service_context_t context = common().session().get_current_service_context();
619 int rc = service_client_stash_set_key(&context, data.data(), (int)data.length());
620 if (rc != 0) CssmError::throwMe(rc);
621 }
622
623 //
624 // The following unlock given an explicit passphrase, rather than using
625 // (special cred sample based) default procedures.
626 //
627 void KeychainDatabase::unlockDb(const CssmData &passphrase)
628 {
629 StLock<Mutex> _(common());
630 makeUnlocked(passphrase);
631 }
632
633 void KeychainDatabase::makeUnlocked(const CssmData &passphrase)
634 {
635 if (isLocked()) {
636 if (decode(passphrase))
637 return;
638 else
639 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
640 } else if (!mValidData) { // need to decode to get our ACLs, passphrase available
641 if (!decode())
642 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
643 }
644
645 if (common().isLoginKeychain()) {
646 bool locked = false;
647 service_context_t context = common().session().get_current_service_context();
648 if (!common().session().keybagGetState(session_keybag_check_master_key) || ((service_client_kb_is_locked(&context, &locked, NULL) == 0) && locked)) {
649 unlock_keybag(common(), passphrase.data(), (int)passphrase.length());
650 }
651 }
652
653 assert(!isLocked());
654 assert(mValidData);
655 }
656
657
658 //
659 // Nonthrowing passphrase-based unlock. This returns false if unlock failed.
660 // Note that this requires an explicitly given passphrase.
661 // Caller must hold common lock.
662 //
663 bool KeychainDatabase::decode(const CssmData &passphrase)
664 {
665 assert(mBlob);
666 common().setup(mBlob, passphrase);
667 bool success = decode();
668 if (success && common().isLoginKeychain()) {
669 unlock_keybag(common(), passphrase.data(), (int)passphrase.length());
670 }
671 return success;
672 }
673
674
675 //
676 // Given the established master secret, decode the working keys and other
677 // functional secrets for this database. Return false (do NOT throw) if
678 // the decode fails. Call this in low(er) level code once you established
679 // the master key.
680 //
681 bool KeychainDatabase::decode()
682 {
683 assert(mBlob);
684 assert(common().hasMaster());
685 void *privateAclBlob;
686 if (common().unlockDb(mBlob, &privateAclBlob)) {
687 if (!mValidData) {
688 acl().importBlob(mBlob->publicAclBlob(), privateAclBlob);
689 mValidData = true;
690 }
691 Allocator::standard().free(privateAclBlob);
692 return true;
693 }
694 secdebug("KCdb", "%p decode failed", this);
695 return false;
696 }
697
698
699 //
700 // Given an AccessCredentials for this database, wring out the existing primary
701 // database secret by whatever means necessary.
702 // On entry, caller must hold the database common lock. It will be held
703 // throughout except when user interaction is required. User interaction
704 // requires relinquishing the database common lock and taking the UI lock. On
705 // return from user interaction, the UI lock is relinquished and the database
706 // common lock must be reacquired. At no time may the caller hold both locks.
707 // On exit, the crypto core has its master secret. If things go wrong,
708 // we will throw a suitable exception. Note that encountering any malformed
709 // credential sample will throw, but this is not guaranteed -- don't assume
710 // that NOT throwing means creds is entirely well-formed (it may just be good
711 // enough to work THIS time).
712 //
713 // How this works:
714 // Walk through the creds. Fish out those credentials (in order) that
715 // are for unlock processing (they have no ACL subject correspondents),
716 // and (try to) obey each in turn, until one produces a valid secret
717 // or you run out. If no special samples are found at all, interpret that as
718 // "use the system global default," which happens to be hard-coded right here.
719 //
720 void KeychainDatabase::establishOldSecrets(const AccessCredentials *creds)
721 {
722 bool forSystem = this->belongsToSystem(); // this keychain belongs to the system security domain
723
724 // attempt system-keychain unlock
725 if (forSystem) {
726 SystemKeychainKey systemKeychain(kSystemUnlockFile);
727 if (systemKeychain.matches(mBlob->randomSignature)) {
728 secdebug("KCdb", "%p attempting system unlock", this);
729 common().setup(mBlob, CssmClient::Key(Server::csp(), systemKeychain.key(), true));
730 if (decode())
731 return;
732 }
733 }
734
735 list<CssmSample> samples;
736 if (creds && creds->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK, samples)) {
737 for (list<CssmSample>::iterator it = samples.begin(); it != samples.end(); it++) {
738 TypedList &sample = *it;
739 sample.checkProper();
740 switch (sample.type()) {
741 // interactively prompt the user - no additional data
742 case CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT:
743 if (!forSystem) {
744 if (interactiveUnlock())
745 return;
746 }
747 break;
748 // try to use an explicitly given passphrase - Data:passphrase
749 case CSSM_SAMPLE_TYPE_PASSWORD:
750 if (sample.length() != 2)
751 CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE);
752 secdebug("KCdb", "%p attempting passphrase unlock", this);
753 if (decode(sample[1]))
754 return;
755 break;
756 // try to open with a given master key - Data:CSP or KeyHandle, Data:CssmKey
757 case CSSM_SAMPLE_TYPE_SYMMETRIC_KEY:
758 case CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY:
759 assert(mBlob);
760 secdebug("KCdb", "%p attempting explicit key unlock", this);
761 common().setup(mBlob, keyFromCreds(sample, 4));
762 if (decode())
763 return;
764 break;
765 // explicitly defeat the default action but don't try anything in particular
766 case CSSM_WORDID_CANCELED:
767 secdebug("KCdb", "%p defeat default action", this);
768 break;
769 default:
770 // Unknown sub-sample for unlocking.
771 // If we wanted to be fascist, we could now do
772 // CssmError::throwMe(CSSM_ERRCODE_SAMPLE_VALUE_NOT_SUPPORTED);
773 // But instead we try to be tolerant and continue on.
774 // This DOES however count as an explicit attempt at specifying unlock,
775 // so we will no longer try the default case below...
776 secdebug("KCdb", "%p unknown sub-sample unlock (%d) ignored", this, sample.type());
777 break;
778 }
779 }
780 } else {
781 // default action
782 assert(mBlob);
783
784 if (!forSystem) {
785 if (interactiveUnlock())
786 return;
787 }
788 }
789
790 // out of options - no secret obtained
791 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
792 }
793
794 bool KeychainDatabase::interactiveUnlock()
795 {
796 secdebug("KCdb", "%p attempting interactive unlock", this);
797 SecurityAgent::Reason reason = SecurityAgent::noReason;
798 QueryUnlock query(*this);
799 // take UI interlock and release DbCommon lock (to avoid deadlocks)
800 StSyncLock<Mutex, Mutex> uisync(common().uiLock(), common());
801
802 // now that we have the UI lock, interact unless another thread unlocked us first
803 if (isLocked()) {
804 query.inferHints(Server::process());
805 reason = query();
806 if (mSaveSecret && reason == SecurityAgent::noReason) {
807 query.retrievePassword(mSecret);
808 }
809 query.disconnect();
810 } else {
811 secdebug("KCdb", "%p was unlocked during uiLock delay", this);
812 }
813
814 if (common().isLoginKeychain()) {
815 bool locked = false;
816 service_context_t context = common().session().get_current_service_context();
817 if ((service_client_kb_is_locked(&context, &locked, NULL) == 0) && locked) {
818 QueryKeybagNewPassphrase keybagQuery(common().session());
819 keybagQuery.inferHints(Server::process());
820 CssmAutoData pass(Allocator::standard(Allocator::sensitive));
821 CssmAutoData oldPass(Allocator::standard(Allocator::sensitive));
822 SecurityAgent::Reason queryReason = keybagQuery.query(oldPass, pass);
823 if (queryReason == SecurityAgent::noReason) {
824 service_client_kb_change_secret(&context, oldPass.data(), (int)oldPass.length(), pass.data(), (int)pass.length());
825 } else if (queryReason == SecurityAgent::resettingPassword) {
826 query.retrievePassword(pass);
827 service_client_kb_reset(&context, pass.data(), (int)pass.length());
828 }
829
830 }
831 }
832
833 return reason == SecurityAgent::noReason;
834 }
835
836
837 //
838 // Same thing, but obtain a new secret somehow and set it into the common.
839 //
840 void KeychainDatabase::establishNewSecrets(const AccessCredentials *creds, SecurityAgent::Reason reason)
841 {
842 list<CssmSample> samples;
843 if (creds && creds->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK, samples)) {
844 for (list<CssmSample>::iterator it = samples.begin(); it != samples.end(); it++) {
845 TypedList &sample = *it;
846 sample.checkProper();
847 switch (sample.type()) {
848 // interactively prompt the user
849 case CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT:
850 {
851 secdebug("KCdb", "%p specified interactive passphrase", this);
852 QueryNewPassphrase query(*this, reason);
853 StSyncLock<Mutex, Mutex> uisync(common().uiLock(), common());
854 query.inferHints(Server::process());
855 CssmAutoData passphrase(Allocator::standard(Allocator::sensitive));
856 CssmAutoData oldPassphrase(Allocator::standard(Allocator::sensitive));
857 if (query(oldPassphrase, passphrase) == SecurityAgent::noReason) {
858 common().setup(NULL, passphrase);
859 change_secret_on_keybag(common(), oldPassphrase.data(), (int)oldPassphrase.length(), passphrase.data(), (int)passphrase.length());
860 return;
861 }
862 }
863 break;
864 // try to use an explicitly given passphrase
865 case CSSM_SAMPLE_TYPE_PASSWORD:
866 {
867 secdebug("KCdb", "%p specified explicit passphrase", this);
868 if (sample.length() != 2)
869 CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE);
870 common().setup(NULL, sample[1]);
871 if (common().isLoginKeychain()) {
872 CssmAutoData oldPassphrase(Allocator::standard(Allocator::sensitive));
873 list<CssmSample> oldSamples;
874 creds->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK, oldSamples);
875 for (list<CssmSample>::iterator oit = oldSamples.begin(); oit != oldSamples.end(); oit++) {
876 TypedList &tmpList = *oit;
877 tmpList.checkProper();
878 if (tmpList.type() == CSSM_SAMPLE_TYPE_PASSWORD) {
879 if (tmpList.length() == 2) {
880 oldPassphrase = tmpList[1].data();
881 }
882 }
883 }
884 if (!oldPassphrase.length() && mSecret && mSecret.length()) {
885 oldPassphrase = mSecret;
886 }
887 change_secret_on_keybag(common(), oldPassphrase.data(), (int)oldPassphrase.length(), sample[1].data().data(), (int)sample[1].data().length());
888 }
889 return;
890 }
891 // try to open with a given master key
892 case CSSM_WORDID_SYMMETRIC_KEY:
893 case CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY:
894 secdebug("KCdb", "%p specified explicit master key", this);
895 common().setup(NULL, keyFromCreds(sample, 3));
896 return;
897 // explicitly defeat the default action but don't try anything in particular
898 case CSSM_WORDID_CANCELED:
899 secdebug("KCdb", "%p defeat default action", this);
900 break;
901 default:
902 // Unknown sub-sample for acquiring new secret.
903 // If we wanted to be fascist, we could now do
904 // CssmError::throwMe(CSSM_ERRCODE_SAMPLE_VALUE_NOT_SUPPORTED);
905 // But instead we try to be tolerant and continue on.
906 // This DOES however count as an explicit attempt at specifying unlock,
907 // so we will no longer try the default case below...
908 secdebug("KCdb", "%p unknown sub-sample acquisition (%d) ignored",
909 this, sample.type());
910 break;
911 }
912 }
913 } else {
914 // default action -- interactive (only)
915 QueryNewPassphrase query(*this, reason);
916 StSyncLock<Mutex, Mutex> uisync(common().uiLock(), common());
917 query.inferHints(Server::process());
918 CssmAutoData passphrase(Allocator::standard(Allocator::sensitive));
919 CssmAutoData oldPassphrase(Allocator::standard(Allocator::sensitive));
920 if (query(oldPassphrase, passphrase) == SecurityAgent::noReason) {
921 common().setup(NULL, passphrase);
922 change_secret_on_keybag(common(), oldPassphrase.data(), (int)oldPassphrase.length(), passphrase.data(), (int)passphrase.length());
923 return;
924 }
925 }
926
927 // out of options - no secret obtained
928 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
929 }
930
931
932 //
933 // Given a (truncated) Database credentials TypedList specifying a master key,
934 // locate the key and return a reference to it.
935 //
936 CssmClient::Key KeychainDatabase::keyFromCreds(const TypedList &sample, unsigned int requiredLength)
937 {
938 // decode TypedList structure (sample type; Data:CSPHandle; Data:CSSM_KEY)
939 assert(sample.type() == CSSM_SAMPLE_TYPE_SYMMETRIC_KEY || sample.type() == CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY);
940 if (sample.length() != requiredLength
941 || sample[1].type() != CSSM_LIST_ELEMENT_DATUM
942 || sample[2].type() != CSSM_LIST_ELEMENT_DATUM
943 || (requiredLength == 4 && sample[3].type() != CSSM_LIST_ELEMENT_DATUM))
944 CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE);
945 KeyHandle &handle = *sample[1].data().interpretedAs<KeyHandle>(CSSM_ERRCODE_INVALID_SAMPLE_VALUE);
946 // We used to be able to check the length but supporting multiple client
947 // architectures dishes that (sizeof(CSSM_KEY) varies due to alignment and
948 // field-size differences). The decoding in the transition layer should
949 // serve as a sufficient garbling check anyway.
950 if (sample[2].data().data() == NULL)
951 CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE);
952 CssmKey &key = *sample[2].data().interpretedAs<CssmKey>();
953
954 if (key.header().cspGuid() == gGuidAppleCSPDL) {
955 // handleOrKey is a SecurityServer KeyHandle; ignore key argument
956 return safer_cast<LocalKey &>(*Server::key(handle));
957 } else
958 if (sample.type() == CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY) {
959 /*
960 Contents (see DefaultCredentials::unlockKey in libsecurity_keychain/defaultcreds.cpp)
961
962 sample[0] sample type
963 sample[1] csp handle for master or wrapping key; is really a keyhandle
964 sample[2] masterKey [not used since securityd cannot interpret; use sample[1] handle instead]
965 sample[3] UnlockReferralRecord data, in this case the flattened symmetric key
966 */
967
968 // RefPointer<Key> Server::key(KeyHandle key)
969 KeyHandle keyhandle = *sample[1].data().interpretedAs<KeyHandle>(CSSM_ERRCODE_INVALID_SAMPLE_VALUE);
970 CssmData &flattenedKey = sample[3].data();
971 RefPointer<Key> unwrappingKey = Server::key(keyhandle);
972 Database &db=unwrappingKey->database();
973
974 CssmKey rawWrappedKey;
975 unflattenKey(flattenedKey, rawWrappedKey);
976
977 RefPointer<Key> masterKey;
978 CssmData emptyDescriptiveData;
979 const AccessCredentials *cred = NULL;
980 const AclEntryPrototype *owner = NULL;
981 CSSM_KEYUSE usage = CSSM_KEYUSE_ANY;
982 CSSM_KEYATTR_FLAGS attrs = CSSM_KEYATTR_EXTRACTABLE; //CSSM_KEYATTR_RETURN_REF |
983
984 // Get default credentials for unwrappingKey (the one on the token)
985 // Copied from Statics::Statics() in libsecurity_keychain/aclclient.cpp
986 // Following KeyItem::getCredentials, one sees that the "operation" parameter
987 // e.g. "CSSM_ACL_AUTHORIZATION_DECRYPT" is ignored
988 Allocator &alloc = Allocator::standard();
989 AutoCredentials promptCred(alloc, 3);// enable interactive prompting
990
991 // promptCred: a credential permitting user prompt confirmations
992 // contains:
993 // a KEYCHAIN_PROMPT sample, both by itself and in a THRESHOLD
994 // a PROMPTED_PASSWORD sample
995 promptCred.sample(0) = TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT);
996 promptCred.sample(1) = TypedList(alloc, CSSM_SAMPLE_TYPE_THRESHOLD,
997 new(alloc) ListElement(TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT)));
998 promptCred.sample(2) = TypedList(alloc, CSSM_SAMPLE_TYPE_PROMPTED_PASSWORD,
999 new(alloc) ListElement(alloc, CssmData()));
1000
1001 // This unwrap object is here just to provide a context
1002 CssmClient::UnwrapKey unwrap(Server::csp(), CSSM_ALGID_NONE); //ok to lie about csp here
1003 unwrap.mode(CSSM_ALGMODE_NONE);
1004 unwrap.padding(CSSM_PADDING_PKCS1);
1005 unwrap.cred(promptCred);
1006 unwrap.add(CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT, uint32(CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7));
1007 Security::Context *tmpContext;
1008 CSSM_CC_HANDLE CCHandle = unwrap.handle();
1009 /*CSSM_RETURN rx = */ CSSM_GetContext (CCHandle, (CSSM_CONTEXT_PTR *)&tmpContext);
1010
1011 // OK, this is skanky but necessary. We overwrite fields in the context struct
1012
1013 tmpContext->ContextType = CSSM_ALGCLASS_ASYMMETRIC;
1014 tmpContext->AlgorithmType = CSSM_ALGID_RSA;
1015
1016 db.unwrapKey(*tmpContext, cred, owner, unwrappingKey, NULL, usage, attrs,
1017 rawWrappedKey, masterKey, emptyDescriptiveData);
1018
1019 Allocator::standard().free(rawWrappedKey.KeyData.Data);
1020
1021 return safer_cast<LocalKey &>(*masterKey).key();
1022 }
1023 else
1024 {
1025 // not a KeyHandle reference; use key as a raw key
1026 if (key.header().blobType() != CSSM_KEYBLOB_RAW)
1027 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE);
1028 if (key.header().keyClass() != CSSM_KEYCLASS_SESSION_KEY)
1029 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
1030 return CssmClient::Key(Server::csp(), key, true);
1031 }
1032 }
1033
1034 void unflattenKey(const CssmData &flatKey, CssmKey &rawKey)
1035 {
1036 // unflatten the raw input key naively: key header then key data
1037 // We also convert it back to host byte order
1038 // A CSSM_KEY is a CSSM_KEYHEADER followed by a CSSM_DATA
1039
1040 // Now copy: header, then key struct, then key data
1041 memcpy(&rawKey.KeyHeader, flatKey.Data, sizeof(CSSM_KEYHEADER));
1042 memcpy(&rawKey.KeyData, flatKey.Data + sizeof(CSSM_KEYHEADER), sizeof(CSSM_DATA));
1043 const uint32 keyDataLength = flatKey.length() - sizeof(CSSM_KEY);
1044 rawKey.KeyData.Data = Allocator::standard().malloc<uint8>(keyDataLength);
1045 rawKey.KeyData.Length = keyDataLength;
1046 memcpy(rawKey.KeyData.Data, flatKey.Data + sizeof(CSSM_KEY), keyDataLength);
1047 Security::n2hi(rawKey.KeyHeader); // convert it to host byte order
1048 }
1049
1050
1051 //
1052 // Verify a putative database passphrase.
1053 // If the database is already unlocked, just check the passphrase.
1054 // Otherwise, unlock with that passphrase and report success.
1055 // Caller must hold the common lock.
1056 //
1057 bool KeychainDatabase::validatePassphrase(const CssmData &passphrase) const
1058 {
1059 if (common().hasMaster()) {
1060 // verify against known secret
1061 return common().validatePassphrase(passphrase);
1062 } else {
1063 // no master secret - perform "blind" unlock to avoid actual unlock
1064 try {
1065 DatabaseCryptoCore test;
1066 test.setup(mBlob, passphrase);
1067 test.decodeCore(mBlob, NULL);
1068 return true;
1069 } catch (...) {
1070 return false;
1071 }
1072 }
1073 }
1074
1075
1076 //
1077 // Lock this database
1078 //
1079 void KeychainDatabase::lockDb()
1080 {
1081 common().lockDb();
1082 }
1083
1084
1085 //
1086 // Given a Key for this database, encode it into a blob and return it.
1087 //
1088 KeyBlob *KeychainDatabase::encodeKey(const CssmKey &key, const CssmData &pubAcl, const CssmData &privAcl)
1089 {
1090 bool inTheClear = false;
1091 if((key.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY) &&
1092 !(key.attribute(CSSM_KEYATTR_PUBLIC_KEY_ENCRYPT))) {
1093 inTheClear = true;
1094 }
1095 StLock<Mutex> _(common());
1096 if(!inTheClear)
1097 makeUnlocked();
1098
1099 // tell the cryptocore to form the key blob
1100 return common().encodeKeyCore(key, pubAcl, privAcl, inTheClear);
1101 }
1102
1103
1104 //
1105 // Given a "blobbed" key for this database, decode it into its real
1106 // key object and (re)populate its ACL.
1107 //
1108 void KeychainDatabase::decodeKey(KeyBlob *blob, CssmKey &key, void * &pubAcl, void * &privAcl)
1109 {
1110 StLock<Mutex> _(common());
1111
1112 if(!blob->isClearText())
1113 makeUnlocked(); // we need our keys
1114
1115 common().decodeKeyCore(blob, key, pubAcl, privAcl);
1116 // memory protocol: pubAcl points into blob; privAcl was allocated
1117
1118 activity();
1119 }
1120
1121 //
1122 // Given a KeychainKey (that implicitly belongs to another keychain),
1123 // return it encoded using this keychain's operational secrets.
1124 //
1125 KeyBlob *KeychainDatabase::recodeKey(KeychainKey &oldKey)
1126 {
1127 if (mRecodingSource != &oldKey.referent<KeychainDatabase>()) {
1128 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
1129 }
1130 oldKey.instantiateAcl(); // make sure key is decoded
1131 CssmData publicAcl, privateAcl;
1132 oldKey.exportBlob(publicAcl, privateAcl);
1133 // NB: blob's memory belongs to caller, not the common
1134
1135 /*
1136 * Make sure the new key is in the same cleartext/encrypted state.
1137 */
1138 bool inTheClear = false;
1139 assert(oldKey.blob());
1140 if(oldKey.blob() && oldKey.blob()->isClearText()) {
1141 /* careful....*/
1142 inTheClear = true;
1143 }
1144 KeyBlob *blob = common().encodeKeyCore(oldKey.cssmKey(), publicAcl, privateAcl, inTheClear);
1145 oldKey.acl().allocator.free(publicAcl);
1146 oldKey.acl().allocator.free(privateAcl);
1147 return blob;
1148 }
1149
1150
1151 //
1152 // Modify database parameters
1153 //
1154 void KeychainDatabase::setParameters(const DBParameters &params)
1155 {
1156 StLock<Mutex> _(common());
1157 makeUnlocked();
1158 common().mParams = params;
1159 common().invalidateBlob(); // invalidate old blobs
1160 activity(); // (also resets the timeout timer)
1161 secdebug("KCdb", "%p common %p(%s) set params=(%u,%u)",
1162 this, &common(), dbName(), params.idleTimeout, params.lockOnSleep);
1163 }
1164
1165
1166 //
1167 // Retrieve database parameters
1168 //
1169 void KeychainDatabase::getParameters(DBParameters &params)
1170 {
1171 StLock<Mutex> _(common());
1172 makeUnlocked();
1173 params = common().mParams;
1174 //activity(); // getting parameters does not reset the idle timer
1175 }
1176
1177
1178 //
1179 // RIGHT NOW, database ACLs are attached to the database.
1180 // This will soon move upstairs.
1181 //
1182 SecurityServerAcl &KeychainDatabase::acl()
1183 {
1184 return *this;
1185 }
1186
1187
1188 //
1189 // Intercept ACL change requests and reset blob validity
1190 //
1191 void KeychainDatabase::instantiateAcl()
1192 {
1193 StLock<Mutex> _(common());
1194 makeUnlocked();
1195 }
1196
1197 void KeychainDatabase::changedAcl()
1198 {
1199 StLock<Mutex> _(common());
1200 version = 0;
1201 }
1202
1203
1204 //
1205 // Check an incoming DbBlob for basic viability
1206 //
1207 void KeychainDatabase::validateBlob(const DbBlob *blob)
1208 {
1209 // perform basic validation on the blob
1210 assert(blob);
1211 blob->validate(CSSMERR_APPLEDL_INVALID_DATABASE_BLOB);
1212 switch (blob->version()) {
1213 #if defined(COMPAT_OSX_10_0)
1214 case DbBlob::version_MacOS_10_0:
1215 break;
1216 #endif
1217 case DbBlob::version_MacOS_10_1:
1218 break;
1219 default:
1220 CssmError::throwMe(CSSMERR_APPLEDL_INCOMPATIBLE_DATABASE_BLOB);
1221 }
1222 }
1223
1224
1225 //
1226 // Debugging support
1227 //
1228 #if defined(DEBUGDUMP)
1229
1230 void KeychainDbCommon::dumpNode()
1231 {
1232 PerSession::dumpNode();
1233 uint32 sig; memcpy(&sig, &mIdentifier.signature(), sizeof(sig));
1234 Debug::dump(" %s[%8.8x]", mIdentifier.dbName(), sig);
1235 if (isLocked()) {
1236 Debug::dump(" locked");
1237 } else {
1238 time_t whenTime = time_t(when());
1239 Debug::dump(" unlocked(%24.24s/%.2g)", ctime(&whenTime),
1240 (when() - Time::now()).seconds());
1241 }
1242 Debug::dump(" params=(%u,%u)", mParams.idleTimeout, mParams.lockOnSleep);
1243 }
1244
1245 void KeychainDatabase::dumpNode()
1246 {
1247 PerProcess::dumpNode();
1248 Debug::dump(" %s vers=%u",
1249 mValidData ? " data" : " nodata", version);
1250 if (mBlob) {
1251 uint32 sig; memcpy(&sig, &mBlob->randomSignature, sizeof(sig));
1252 Debug::dump(" blob=%p[%8.8x]", mBlob, sig);
1253 } else {
1254 Debug::dump(" noblob");
1255 }
1256 }
1257
1258 #endif //DEBUGDUMP
1259
1260
1261 //
1262 // DbCommon basic features
1263 //
1264 KeychainDbCommon::KeychainDbCommon(Session &ssn, const DbIdentifier &id)
1265 : LocalDbCommon(ssn), sequence(0), version(1), mIdentifier(id),
1266 mIsLocked(true), mValidParams(false), mLoginKeychain(false)
1267 {
1268 // match existing DbGlobal or create a new one
1269 {
1270 Server &server = Server::active();
1271 StLock<Mutex> _(server);
1272 if (KeychainDbGlobal *dbglobal =
1273 server.findFirst<KeychainDbGlobal, const DbIdentifier &>(&KeychainDbGlobal::identifier, identifier())) {
1274 parent(*dbglobal);
1275 secdebug("KCdb", "%p linking to existing DbGlobal %p", this, dbglobal);
1276 } else {
1277 // DbGlobal not present; make a new one
1278 parent(*new KeychainDbGlobal(identifier()));
1279 secdebug("KCdb", "%p linking to new DbGlobal %p", this, &global());
1280 }
1281
1282 // link lifetime to the Session
1283 session().addReference(*this);
1284
1285 if (strcasestr(id.dbName(), "login.keychain") != NULL) {
1286 mLoginKeychain = true;
1287 }
1288 }
1289
1290 if (mLoginKeychain && !session().keybagGetState(session_keybag_loaded)) {
1291 service_context_t context = session().get_current_service_context();
1292 if (service_client_kb_load(&context) == 0) {
1293 session().keybagSetState(session_keybag_loaded);
1294 }
1295 }
1296 }
1297
1298 KeychainDbCommon::~KeychainDbCommon()
1299 {
1300 SECURITYD_KEYCHAIN_RELEASE(this, (char*)this->dbName());
1301
1302 // explicitly unschedule ourselves
1303 Server::active().clearTimer(this);
1304 if (mLoginKeychain) {
1305 session().keybagClearState(session_keybag_unlocked);
1306 }
1307 }
1308
1309 KeychainDbGlobal &KeychainDbCommon::global() const
1310 {
1311 return parent<KeychainDbGlobal>();
1312 }
1313
1314
1315 void KeychainDbCommon::select()
1316 { this->ref(); }
1317
1318 void KeychainDbCommon::unselect()
1319 { this->unref(); }
1320
1321
1322
1323 void KeychainDbCommon::makeNewSecrets()
1324 {
1325 // we already have a master key (right?)
1326 assert(hasMaster());
1327
1328 // tell crypto core to generate the use keys
1329 DatabaseCryptoCore::generateNewSecrets();
1330
1331 // we're now officially "unlocked"; set the timer
1332 setUnlocked();
1333 }
1334
1335
1336 //
1337 // All unlocking activity ultimately funnels through this method.
1338 // This unlocks a DbCommon using the secrets setup in its crypto core
1339 // component, and performs all the housekeeping needed to represent
1340 // the state change.
1341 // Returns true if unlock was successful, false if it failed due to
1342 // invalid/insufficient secrets. Throws on other errors.
1343 //
1344 bool KeychainDbCommon::unlockDb(DbBlob *blob, void **privateAclBlob)
1345 {
1346 try {
1347 // Tell the cryptocore to (try to) decode itself. This will fail
1348 // in an astonishing variety of ways if the passphrase is wrong.
1349 assert(hasMaster());
1350 decodeCore(blob, privateAclBlob);
1351 secdebug("KCdb", "%p unlock successful", this);
1352 } catch (...) {
1353 secdebug("KCdb", "%p unlock failed", this);
1354 return false;
1355 }
1356
1357 // get the database parameters only if we haven't got them yet
1358 if (!mValidParams) {
1359 mParams = blob->params;
1360 n2hi(mParams.idleTimeout);
1361 mValidParams = true; // sticky
1362 }
1363
1364 bool isLocked = mIsLocked;
1365
1366 setUnlocked(); // mark unlocked
1367
1368 if (isLocked) {
1369 // broadcast unlock notification, but only if we were previously locked
1370 notify(kNotificationEventUnlocked);
1371 SECURITYD_KEYCHAIN_UNLOCK(this, (char*)this->dbName());
1372 }
1373 return true;
1374 }
1375
1376 void KeychainDbCommon::setUnlocked()
1377 {
1378 session().addReference(*this); // active/held
1379 mIsLocked = false; // mark unlocked
1380 activity(); // set timeout timer
1381 }
1382
1383
1384 void KeychainDbCommon::lockDb()
1385 {
1386 bool lock = false;
1387 {
1388 StLock<Mutex> _(*this);
1389 if (!isLocked()) {
1390 DatabaseCryptoCore::invalidate();
1391 notify(kNotificationEventLocked);
1392 SECURITYD_KEYCHAIN_LOCK(this, (char*)this->dbName());
1393 Server::active().clearTimer(this);
1394
1395 mIsLocked = true; // mark locked
1396 lock = true;
1397
1398 // this call may destroy us if we have no databases anymore
1399 session().removeReference(*this);
1400 }
1401 }
1402
1403 if (mLoginKeychain && lock) {
1404 service_context_t context = session().get_current_service_context();
1405 service_client_kb_lock(&context);
1406 session().keybagClearState(session_keybag_unlocked);
1407 }
1408 }
1409
1410
1411 DbBlob *KeychainDbCommon::encode(KeychainDatabase &db)
1412 {
1413 assert(!isLocked()); // must have been unlocked by caller
1414
1415 // export database ACL to blob form
1416 CssmData pubAcl, privAcl;
1417 db.acl().exportBlob(pubAcl, privAcl);
1418
1419 // tell the cryptocore to form the blob
1420 DbBlob form;
1421 form.randomSignature = identifier();
1422 form.sequence = sequence;
1423 form.params = mParams;
1424 h2ni(form.params.idleTimeout);
1425
1426 assert(hasMaster());
1427 DbBlob *blob = encodeCore(form, pubAcl, privAcl);
1428
1429 // clean up and go
1430 db.acl().allocator.free(pubAcl);
1431 db.acl().allocator.free(privAcl);
1432 return blob;
1433 }
1434
1435
1436 //
1437 // Perform deferred lock processing for a database.
1438 //
1439 void KeychainDbCommon::action()
1440 {
1441 secdebug("KCdb", "common %s(%p) locked by timer", dbName(), this);
1442 lockDb();
1443 }
1444
1445 void KeychainDbCommon::activity()
1446 {
1447 if (!isLocked()) {
1448 secdebug("KCdb", "setting DbCommon %p timer to %d",
1449 this, int(mParams.idleTimeout));
1450 Server::active().setTimer(this, Time::Interval(int(mParams.idleTimeout)));
1451 }
1452 }
1453
1454 void KeychainDbCommon::sleepProcessing()
1455 {
1456 secdebug("KCdb", "common %s(%p) sleep-lock processing", dbName(), this);
1457 StLock<Mutex> _(*this);
1458 if (mParams.lockOnSleep)
1459 lockDb();
1460 }
1461
1462 void KeychainDbCommon::lockProcessing()
1463 {
1464 lockDb();
1465 }
1466
1467
1468 //
1469 // We consider a keychain to belong to the system domain if it resides
1470 // in /Library/Keychains. That's not exactly fool-proof, but we don't
1471 // currently have any internal markers to interrogate.
1472 //
1473 bool KeychainDbCommon::belongsToSystem() const
1474 {
1475 if (const char *name = this->dbName())
1476 return !strncmp(name, "/Library/Keychains/", 19);
1477 return false;
1478 }
1479
1480
1481 //
1482 // Keychain global objects
1483 //
1484 KeychainDbGlobal::KeychainDbGlobal(const DbIdentifier &id)
1485 : mIdentifier(id)
1486 {
1487 }
1488
1489 KeychainDbGlobal::~KeychainDbGlobal()
1490 {
1491 secdebug("KCdb", "DbGlobal %p destroyed", this);
1492 }