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