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