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