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