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