]> git.saurik.com Git - apple/securityd.git/blob - src/kcdatabase.cpp
securityd-36489.tar.gz
[apple/securityd.git] / src / kcdatabase.cpp
1 /*
2 * Copyright (c) 2000-2007 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_agent_client/agentclient.h>
48 #include <security_cdsa_utilities/acl_any.h> // for default owner ACLs
49 #include <security_cdsa_utilities/cssmendian.h>
50 #include <security_cdsa_client/wrapkey.h>
51 #include <security_cdsa_client/genkey.h>
52 #include <security_cdsa_client/signclient.h>
53 #include <security_cdsa_client/cryptoclient.h>
54 #include <security_cdsa_client/macclient.h>
55 #include <securityd_client/dictionary.h>
56 #include <security_utilities/endian.h>
57
58 void unflattenKey(const CssmData &flatKey, CssmKey &rawKey); //>> make static method on KeychainDatabase
59
60 //
61 // Create a Database object from initial parameters (create operation)
62 //
63 KeychainDatabase::KeychainDatabase(const DLDbIdentifier &id, const DBParameters &params, Process &proc,
64 const AccessCredentials *cred, const AclEntryPrototype *owner)
65 : LocalDatabase(proc), mValidData(false), version(0), mBlob(NULL)
66 {
67 // save a copy of the credentials for later access control
68 mCred = DataWalkers::copy(cred, Allocator::standard());
69
70 // create a new random signature to complete the DLDbIdentifier
71 DbBlob::Signature newSig;
72 Server::active().random(newSig.bytes);
73 DbIdentifier ident(id, newSig);
74
75 // create common block and initialize
76 RefPointer<KeychainDbCommon> newCommon = new KeychainDbCommon(proc.session(), ident);
77 StLock<Mutex> _(*newCommon);
78 parent(*newCommon);
79 // new common is now visible (in ident-map) but we hold its lock
80
81 // establish the new master secret
82 establishNewSecrets(cred, SecurityAgent::newDatabase);
83
84 // set initial database parameters
85 common().mParams = params;
86
87 // the common is "unlocked" now
88 common().makeNewSecrets();
89
90 // establish initial ACL
91 if (owner)
92 acl().cssmSetInitial(*owner);
93 else
94 acl().cssmSetInitial(new AnyAclSubject());
95 mValidData = true;
96
97 // for now, create the blob immediately
98 encode();
99
100 proc.addReference(*this);
101
102 // this new keychain is unlocked; make it so
103 activity();
104
105 secdebug("KCdb", "database %s(%p) created, common at %p",
106 common().dbName(), this, &common());
107 }
108
109
110 //
111 // Create a Database object from a database blob (decoding)
112 //
113 KeychainDatabase::KeychainDatabase(const DLDbIdentifier &id, const DbBlob *blob, Process &proc,
114 const AccessCredentials *cred)
115 : LocalDatabase(proc), mValidData(false), version(0)
116 {
117 validateBlob(blob);
118
119 // save a copy of the credentials for later access control
120 mCred = DataWalkers::copy(cred, Allocator::standard());
121 mBlob = blob->copy();
122
123 // check to see if we already know about this database
124 DbIdentifier ident(id, blob->randomSignature);
125 Session &session = process().session();
126 StLock<Mutex> _(session);
127 if (KeychainDbCommon *dbcom =
128 session.findFirst<KeychainDbCommon, const DbIdentifier &>(&KeychainDbCommon::identifier, ident)) {
129 parent(*dbcom);
130 //@@@ arbitrate sequence number here, perhaps update common().mParams
131 secdebug("KCdb",
132 "open database %s(%p) version %x at known common %p",
133 common().dbName(), this, blob->version(), &common());
134 } else {
135 // DbCommon not present; make a new one
136 parent(*new KeychainDbCommon(proc.session(), ident));
137 common().mParams = blob->params;
138 secdebug("KCdb", "open database %s(%p) version %x with new common %p",
139 common().dbName(), this, blob->version(), &common());
140 // this DbCommon is locked; no timer or reference setting
141 }
142 proc.addReference(*this);
143 }
144
145
146 //
147 // Special-purpose constructor for keychain synchronization. Copies an
148 // existing keychain but uses the operational keys from secretsBlob. The
149 // new KeychainDatabase will silently replace the existing KeychainDatabase
150 // as soon as the client declares that re-encoding of all keychain items is
151 // finished. This is a little perilous since it allows a client to dictate
152 // securityd state, but we try to ensure that only the client that started
153 // the re-encoding can declare it done.
154 //
155 KeychainDatabase::KeychainDatabase(KeychainDatabase &src, Process &proc,
156 const DbBlob *secretsBlob, const CssmData &agentData)
157 : LocalDatabase(proc), mValidData(false), version(0), mBlob(NULL)
158 {
159 validateBlob(secretsBlob);
160
161 // get the passphrase to unlock secretsBlob
162 QueryDBBlobSecret query;
163 query.inferHints(proc);
164 query.addHint(AGENT_HINT_KCSYNC_DICT, agentData.data(), agentData.length());
165 DatabaseCryptoCore keysCore;
166 if (query(keysCore, secretsBlob) != SecurityAgent::noReason)
167 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
168 // keysCore is now ready to yield its secrets to us
169
170 mCred = DataWalkers::copy(src.mCred, Allocator::standard());
171
172 // Give this KeychainDatabase a temporary name
173 std::string newDbName = std::string("////") + std::string(src.identifier().dbName());
174 DLDbIdentifier newDLDbIdent(src.identifier().dlDbIdentifier().ssuid(), newDbName.c_str(), src.identifier().dlDbIdentifier().dbLocation());
175 DbIdentifier ident(newDLDbIdent, src.identifier());
176
177 // create common block and initialize
178 RefPointer<KeychainDbCommon> newCommon = new KeychainDbCommon(proc.session(), ident);
179 StLock<Mutex> _(*newCommon);
180 parent(*newCommon);
181
182 // set initial database parameters from the source keychain
183 common().mParams = src.common().mParams;
184
185 // establish the source keychain's master secret as ours
186 // @@@ NB: this is a v. 0.1 assumption. We *should* trigger new UI
187 // that offers the user the option of using the existing password
188 // or choosing a new one. That would require a new
189 // SecurityAgentQuery type, new UI, and--possibly--modifications to
190 // ensure that the new password is available here to generate the
191 // new master secret.
192 src.unlockDb(); // precaution for masterKey()
193 common().setup(src.blob(), src.common().masterKey());
194
195 // import the operational secrets
196 common().importSecrets(keysCore);
197
198 // import source keychain's ACL
199 CssmData pubAcl, privAcl;
200 src.acl().exportBlob(pubAcl, privAcl);
201 importBlob(pubAcl.data(), privAcl.data());
202 src.acl().allocator.free(pubAcl);
203 src.acl().allocator.free(privAcl);
204
205 // indicate that this keychain should be allowed to do some otherwise
206 // risky things required for copying, like re-encoding keys
207 mRecodingSource = &src;
208
209 common().setUnlocked();
210 mValidData = true;
211
212 encode();
213
214 proc.addReference(*this);
215 secdebug("SSdb", "database %s(%p) created as copy, common at %p",
216 common().dbName(), this, &common());
217 }
218
219
220 //
221 // Destroy a Database
222 //
223 KeychainDatabase::~KeychainDatabase()
224 {
225 secdebug("KCdb", "deleting database %s(%p) common %p",
226 common().dbName(), this, &common());
227 Allocator::standard().free(mCred);
228 Allocator::standard().free(mBlob);
229 }
230
231
232 //
233 // Basic Database virtual implementations
234 //
235 KeychainDbCommon &KeychainDatabase::common() const
236 {
237 return parent<KeychainDbCommon>();
238 }
239
240 const char *KeychainDatabase::dbName() const
241 {
242 return common().dbName();
243 }
244
245 bool KeychainDatabase::transient() const
246 {
247 return false; // has permanent store
248 }
249
250 AclKind KeychainDatabase::aclKind() const
251 {
252 return dbAcl;
253 }
254
255 Database *KeychainDatabase::relatedDatabase()
256 {
257 return this;
258 }
259
260
261 static inline KeychainKey &myKey(Key *key)
262 {
263 return *safe_cast<KeychainKey *>(key);
264 }
265
266
267 //
268 // (Re-)Authenticate the database. This changes the stored credentials.
269 //
270 void KeychainDatabase::authenticate(CSSM_DB_ACCESS_TYPE mode,
271 const AccessCredentials *cred)
272 {
273 StLock<Mutex> _(common());
274
275 // the (Apple specific) RESET bit means "lock the database now"
276 switch (mode) {
277 case CSSM_DB_ACCESS_RESET:
278 secdebug("KCdb", "%p ACCESS_RESET triggers keychain lock", this);
279 common().lockDb();
280 break;
281 default:
282 // store the new credentials for future use
283 secdebug("KCdb", "%p authenticate stores new database credentials", this);
284 AccessCredentials *newCred = DataWalkers::copy(cred, Allocator::standard());
285 Allocator::standard().free(mCred);
286 mCred = newCred;
287 }
288 }
289
290
291 //
292 // Make a new KeychainKey.
293 // If PERMANENT is off, make a temporary key instead.
294 // The db argument allows you to create for another KeychainDatabase (only);
295 // it defaults to ourselves.
296 //
297 RefPointer<Key> KeychainDatabase::makeKey(Database &db, const CssmKey &newKey,
298 uint32 moreAttributes, const AclEntryPrototype *owner)
299 {
300
301 if (moreAttributes & CSSM_KEYATTR_PERMANENT)
302 return new KeychainKey(db, newKey, moreAttributes, owner);
303 else
304 return process().makeTemporaryKey(newKey, moreAttributes, owner);
305 }
306
307 RefPointer<Key> KeychainDatabase::makeKey(const CssmKey &newKey,
308 uint32 moreAttributes, const AclEntryPrototype *owner)
309 {
310 return makeKey(*this, newKey, moreAttributes, owner);
311 }
312
313
314 //
315 // Return the database blob, recalculating it as needed.
316 //
317 DbBlob *KeychainDatabase::blob()
318 {
319 StLock<Mutex> _(common());
320 if (!validBlob()) {
321 makeUnlocked(); // unlock to get master secret
322 encode(); // (re)encode blob if needed
323 }
324 activity(); // reset timeout
325 assert(validBlob()); // better have a valid blob now...
326 return mBlob;
327 }
328
329
330 //
331 // Encode the current database as a blob.
332 // Note that this returns memory we own and keep.
333 // Caller must hold common lock.
334 //
335 void KeychainDatabase::encode()
336 {
337 DbBlob *blob = common().encode(*this);
338 Allocator::standard().free(mBlob);
339 mBlob = blob;
340 version = common().version;
341 secdebug("KCdb", "encoded database %p common %p(%s) version %u params=(%u,%u)",
342 this, &common(), dbName(), version,
343 common().mParams.idleTimeout, common().mParams.lockOnSleep);
344 }
345
346
347 //
348 // Change the passphrase on a database
349 //
350 void KeychainDatabase::changePassphrase(const AccessCredentials *cred)
351 {
352 // get and hold the common lock (don't let other threads break in here)
353 StLock<Mutex> _(common());
354
355 // establish OLD secret - i.e. unlock the database
356 //@@@ do we want to leave the final lock state alone?
357 makeUnlocked(cred);
358
359 // establish NEW secret
360 establishNewSecrets(cred, SecurityAgent::changePassphrase);
361 common().invalidateBlob(); // blob state changed
362 secdebug("KCdb", "Database %s(%p) master secret changed", common().dbName(), this);
363 encode(); // force rebuild of local blob
364
365 // send out a notification
366 notify(kNotificationEventPassphraseChanged);
367
368 // I guess this counts as an activity
369 activity();
370 }
371
372 //
373 // Second stage of keychain synchronization: overwrite the original keychain's
374 // (this KeychainDatabase's) operational secrets
375 //
376 void KeychainDatabase::commitSecretsForSync(KeychainDatabase &cloneDb)
377 {
378 StLock<Mutex> _(common());
379
380 // try to detect spoofing
381 if (cloneDb.mRecodingSource != this)
382 CssmError::throwMe(CSSM_ERRCODE_INVALID_DB_HANDLE);
383
384 // in case we autolocked since starting the sync
385 unlockDb();
386 cloneDb.unlockDb();
387
388 // Decode all keys whose handles refer to this on-disk keychain so that
389 // if the holding client commits the key back to disk, it's encoded with
390 // the new operational secrets. The recoding client *must* hold a write
391 // lock for the on-disk keychain from the moment it starts recoding key
392 // items until after this call.
393 //
394 // @@@ This specific implementation is a workaround for 4003540.
395 std::vector<CSSM_HANDLE> handleList;
396 HandleObject::findAllRefs<KeychainKey>(handleList);
397 size_t count = handleList.size();
398 if (count > 0) {
399 for (unsigned int n = 0; n < count; ++n) {
400 RefPointer<KeychainKey> kckey =
401 HandleObject::findRefAndLock<KeychainKey>(handleList[n], CSSMERR_CSP_INVALID_KEY_REFERENCE);
402 StLock<Mutex> _(*kckey/*, true*/);
403 if (kckey->database().global().identifier() == identifier()) {
404 kckey->key(); // force decode
405 kckey->invalidateBlob();
406 secdebug("kcrecode", "changed extant key %p (proc %d)",
407 &*kckey, kckey->process().pid());
408 }
409 }
410 }
411
412 // it is now safe to replace the old op secrets
413 common().importSecrets(cloneDb.common());
414 common().invalidateBlob();
415 }
416
417
418 //
419 // Extract the database master key as a proper Key object.
420 //
421 RefPointer<Key> KeychainDatabase::extractMasterKey(Database &db,
422 const AccessCredentials *cred, const AclEntryPrototype *owner,
423 uint32 usage, uint32 attrs)
424 {
425 // get and hold common lock
426 StLock<Mutex> _(common());
427
428 // force lock to require re-validation of credentials
429 lockDb();
430
431 // unlock to establish master secret
432 makeUnlocked();
433
434 // extract the raw cryptographic key
435 CssmClient::WrapKey wrap(Server::csp(), CSSM_ALGID_NONE);
436 CssmKey key;
437 wrap(common().masterKey(), key);
438
439 // make the key object and return it
440 return makeKey(db, key, attrs & LocalKey::managedAttributes, owner);
441 }
442
443
444 //
445 // Unlock this database (if needed) by obtaining the master secret in some
446 // suitable way and then proceeding to unlock with it.
447 // Does absolutely nothing if the database is already unlocked.
448 // The makeUnlocked forms are identical except the assume the caller already
449 // holds the common lock.
450 //
451 void KeychainDatabase::unlockDb()
452 {
453 StLock<Mutex> _(common());
454 makeUnlocked();
455 }
456
457 void KeychainDatabase::makeUnlocked()
458 {
459 return makeUnlocked(mCred);
460 }
461
462 void KeychainDatabase::makeUnlocked(const AccessCredentials *cred)
463 {
464 if (isLocked()) {
465 secdebug("KCdb", "%p(%p) unlocking for makeUnlocked()", this, &common());
466 assert(mBlob || (mValidData && common().hasMaster()));
467 establishOldSecrets(cred);
468 common().setUnlocked(); // mark unlocked
469 }
470 if (!mValidData) { // need to decode to get our ACLs, master secret available
471 secdebug("KCdb", "%p(%p) is unlocked; decoding for makeUnlocked()", this, &common());
472 if (!decode())
473 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
474 }
475 assert(!isLocked());
476 assert(mValidData);
477 }
478
479
480 //
481 // The following unlock given an explicit passphrase, rather than using
482 // (special cred sample based) default procedures.
483 //
484 void KeychainDatabase::unlockDb(const CssmData &passphrase)
485 {
486 StLock<Mutex> _(common());
487 makeUnlocked(passphrase);
488 }
489
490 void KeychainDatabase::makeUnlocked(const CssmData &passphrase)
491 {
492 if (isLocked()) {
493 if (decode(passphrase))
494 return;
495 else
496 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
497 } else if (!mValidData) { // need to decode to get our ACLs, passphrase available
498 if (!decode())
499 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
500 }
501 assert(!isLocked());
502 assert(mValidData);
503 }
504
505
506 //
507 // Nonthrowing passphrase-based unlock. This returns false if unlock failed.
508 // Note that this requires an explicitly given passphrase.
509 // Caller must hold common lock.
510 //
511 bool KeychainDatabase::decode(const CssmData &passphrase)
512 {
513 assert(mBlob);
514 common().setup(mBlob, passphrase);
515 return decode();
516 }
517
518
519 //
520 // Given the established master secret, decode the working keys and other
521 // functional secrets for this database. Return false (do NOT throw) if
522 // the decode fails. Call this in low(er) level code once you established
523 // the master key.
524 //
525 bool KeychainDatabase::decode()
526 {
527 assert(mBlob);
528 assert(common().hasMaster());
529 void *privateAclBlob;
530 if (common().unlockDb(mBlob, &privateAclBlob)) {
531 if (!mValidData) {
532 acl().importBlob(mBlob->publicAclBlob(), privateAclBlob);
533 mValidData = true;
534 }
535 Allocator::standard().free(privateAclBlob);
536 return true;
537 }
538 secdebug("KCdb", "%p decode failed", this);
539 return false;
540 }
541
542
543 //
544 // Given an AccessCredentials for this database, wring out the existing primary
545 // database secret by whatever means necessary.
546 // On entry, caller must hold the database common lock. It will be held
547 // throughout except when user interaction is required. User interaction
548 // requires relinquishing the database common lock and taking the UI lock. On
549 // return from user interaction, the UI lock is relinquished and the database
550 // common lock must be reacquired. At no time may the caller hold both locks.
551 // On exit, the crypto core has its master secret. If things go wrong,
552 // we will throw a suitable exception. Note that encountering any malformed
553 // credential sample will throw, but this is not guaranteed -- don't assume
554 // that NOT throwing means creds is entirely well-formed (it may just be good
555 // enough to work THIS time).
556 //
557 // How this works:
558 // Walk through the creds. Fish out those credentials (in order) that
559 // are for unlock processing (they have no ACL subject correspondents),
560 // and (try to) obey each in turn, until one produces a valid secret
561 // or you run out. If no special samples are found at all, interpret that as
562 // "use the system global default," which happens to be hard-coded right here.
563 //
564 void KeychainDatabase::establishOldSecrets(const AccessCredentials *creds)
565 {
566 list<CssmSample> samples;
567 if (creds && creds->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK, samples)) {
568 for (list<CssmSample>::iterator it = samples.begin(); it != samples.end(); it++) {
569 TypedList &sample = *it;
570 sample.checkProper();
571 switch (sample.type()) {
572 // interactively prompt the user - no additional data
573 case CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT:
574 if (interactiveUnlock())
575 return;
576 break;
577 // try to use an explicitly given passphrase - Data:passphrase
578 case CSSM_SAMPLE_TYPE_PASSWORD:
579 if (sample.length() != 2)
580 CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE);
581 secdebug("KCdb", "%p attempting passphrase unlock", this);
582 if (decode(sample[1]))
583 return;
584 break;
585 // try to open with a given master key - Data:CSP or KeyHandle, Data:CssmKey
586 case CSSM_SAMPLE_TYPE_SYMMETRIC_KEY:
587 case CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY:
588 assert(mBlob);
589 secdebug("KCdb", "%p attempting explicit key unlock", this);
590 common().setup(mBlob, keyFromCreds(sample, 4));
591 if (decode())
592 return;
593 break;
594 // explicitly defeat the default action but don't try anything in particular
595 case CSSM_WORDID_CANCELED:
596 secdebug("KCdb", "%p defeat default action", this);
597 break;
598 default:
599 // Unknown sub-sample for unlocking.
600 // If we wanted to be fascist, we could now do
601 // CssmError::throwMe(CSSM_ERRCODE_SAMPLE_VALUE_NOT_SUPPORTED);
602 // But instead we try to be tolerant and continue on.
603 // This DOES however count as an explicit attempt at specifying unlock,
604 // so we will no longer try the default case below...
605 secdebug("KCdb", "%p unknown sub-sample unlock (%d) ignored", this, sample.type());
606 break;
607 }
608 }
609 } else {
610 // default action
611 assert(mBlob);
612
613 // attempt system-keychain unlock
614 SystemKeychainKey systemKeychain(kSystemUnlockFile);
615 if (systemKeychain.matches(mBlob->randomSignature)) {
616 secdebug("KCdb", "%p attempting system unlock", this);
617 common().setup(mBlob, CssmClient::Key(Server::csp(), systemKeychain.key(), true));
618 if (decode())
619 return;
620 }
621
622 if (interactiveUnlock())
623 return;
624 }
625
626 // out of options - no secret obtained
627 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
628 }
629
630 bool KeychainDatabase::interactiveUnlock()
631 {
632 secdebug("KCdb", "%p attempting interactive unlock", this);
633 QueryUnlock query(*this);
634 // take UI interlock and release DbCommon lock (to avoid deadlocks)
635 StSyncLock<Mutex, Mutex> uisync(common().uiLock(), common());
636
637 // now that we have the UI lock, interact unless another thread unlocked us first
638 if (isLocked()) {
639 query.inferHints(Server::process());
640 return query() == SecurityAgent::noReason;
641 } else {
642 secdebug("KCdb", "%p was unlocked during uiLock delay", this);
643 return true;
644 }
645 }
646
647
648 //
649 // Same thing, but obtain a new secret somehow and set it into the common.
650 //
651 void KeychainDatabase::establishNewSecrets(const AccessCredentials *creds, SecurityAgent::Reason reason)
652 {
653 list<CssmSample> samples;
654 if (creds && creds->samples().collect(CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK, samples)) {
655 for (list<CssmSample>::iterator it = samples.begin(); it != samples.end(); it++) {
656 TypedList &sample = *it;
657 sample.checkProper();
658 switch (sample.type()) {
659 // interactively prompt the user
660 case CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT:
661 {
662 secdebug("KCdb", "%p specified interactive passphrase", this);
663 QueryNewPassphrase query(*this, reason);
664 StSyncLock<Mutex, Mutex> uisync(common().uiLock(), common());
665 query.inferHints(Server::process());
666 CssmAutoData passphrase(Allocator::standard(Allocator::sensitive));
667 if (query(passphrase) == SecurityAgent::noReason) {
668 common().setup(NULL, passphrase);
669 return;
670 }
671 }
672 break;
673 // try to use an explicitly given passphrase
674 case CSSM_SAMPLE_TYPE_PASSWORD:
675 secdebug("KCdb", "%p specified explicit passphrase", this);
676 if (sample.length() != 2)
677 CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE);
678 common().setup(NULL, sample[1]);
679 return;
680 // try to open with a given master key
681 case CSSM_WORDID_SYMMETRIC_KEY:
682 case CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY:
683 secdebug("KCdb", "%p specified explicit master key", this);
684 common().setup(NULL, keyFromCreds(sample, 3));
685 return;
686 // explicitly defeat the default action but don't try anything in particular
687 case CSSM_WORDID_CANCELED:
688 secdebug("KCdb", "%p defeat default action", this);
689 break;
690 default:
691 // Unknown sub-sample for acquiring new secret.
692 // If we wanted to be fascist, we could now do
693 // CssmError::throwMe(CSSM_ERRCODE_SAMPLE_VALUE_NOT_SUPPORTED);
694 // But instead we try to be tolerant and continue on.
695 // This DOES however count as an explicit attempt at specifying unlock,
696 // so we will no longer try the default case below...
697 secdebug("KCdb", "%p unknown sub-sample acquisition (%d) ignored",
698 this, sample.type());
699 break;
700 }
701 }
702 } else {
703 // default action -- interactive (only)
704 QueryNewPassphrase query(*this, reason);
705 StSyncLock<Mutex, Mutex> uisync(common().uiLock(), common());
706 query.inferHints(Server::process());
707 CssmAutoData passphrase(Allocator::standard(Allocator::sensitive));
708 if (query(passphrase) == SecurityAgent::noReason) {
709 common().setup(NULL, passphrase);
710 return;
711 }
712 }
713
714 // out of options - no secret obtained
715 CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
716 }
717
718
719 //
720 // Given a (truncated) Database credentials TypedList specifying a master key,
721 // locate the key and return a reference to it.
722 //
723 CssmClient::Key KeychainDatabase::keyFromCreds(const TypedList &sample, unsigned int requiredLength)
724 {
725 // decode TypedList structure (sample type; Data:CSPHandle; Data:CSSM_KEY)
726 assert(sample.type() == CSSM_SAMPLE_TYPE_SYMMETRIC_KEY || sample.type() == CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY);
727 if (sample.length() != requiredLength
728 || sample[1].type() != CSSM_LIST_ELEMENT_DATUM
729 || sample[2].type() != CSSM_LIST_ELEMENT_DATUM
730 || (requiredLength == 4 && sample[3].type() != CSSM_LIST_ELEMENT_DATUM))
731 CssmError::throwMe(CSSM_ERRCODE_INVALID_SAMPLE_VALUE);
732 CSSM_CSP_HANDLE &handle = *sample[1].data().interpretedAs<CSSM_CSP_HANDLE>(CSSM_ERRCODE_INVALID_SAMPLE_VALUE);
733 CssmKey &key = *sample[2].data().interpretedAs<CssmKey>(CSSM_ERRCODE_INVALID_SAMPLE_VALUE);
734
735 if (key.header().cspGuid() == gGuidAppleCSPDL) {
736 // handleOrKey is a SecurityServer KeyHandle; ignore key argument
737 return safer_cast<LocalKey &>(*Server::key(handle));
738 } else
739 if (sample.type() == CSSM_SAMPLE_TYPE_ASYMMETRIC_KEY) {
740 /*
741 Contents (see DefaultCredentials::unlockKey in libsecurity_keychain/defaultcreds.cpp)
742
743 sample[0] sample type
744 sample[1] csp handle for master or wrapping key; is really a keyhandle
745 sample[2] masterKey [not used since securityd cannot interpret; use sample[1] handle instead]
746 sample[3] UnlockReferralRecord data, in this case the flattened symmetric key
747 */
748
749 // RefPointer<Key> Server::key(KeyHandle key)
750 KeyHandle keyhandle = *sample[1].data().interpretedAs<KeyHandle>(CSSM_ERRCODE_INVALID_SAMPLE_VALUE);
751 CssmData &flattenedKey = sample[3].data();
752 RefPointer<Key> unwrappingKey = Server::key(keyhandle);
753 Database &db=unwrappingKey->database();
754
755 CssmKey rawWrappedKey;
756 unflattenKey(flattenedKey, rawWrappedKey);
757
758 RefPointer<Key> masterKey;
759 CssmData emptyDescriptiveData;
760 const AccessCredentials *cred = NULL;
761 const AclEntryPrototype *owner = NULL;
762 CSSM_KEYUSE usage = CSSM_KEYUSE_ANY;
763 CSSM_KEYATTR_FLAGS attrs = CSSM_KEYATTR_EXTRACTABLE; //CSSM_KEYATTR_RETURN_REF |
764
765 // Get default credentials for unwrappingKey (the one on the token)
766 // Copied from Statics::Statics() in libsecurity_keychain/aclclient.cpp
767 // Following KeyItem::getCredentials, one sees that the "operation" parameter
768 // e.g. "CSSM_ACL_AUTHORIZATION_DECRYPT" is ignored
769 Allocator &alloc = Allocator::standard();
770 AutoCredentials promptCred(alloc, 3);// enable interactive prompting
771
772 // promptCred: a credential permitting user prompt confirmations
773 // contains:
774 // a KEYCHAIN_PROMPT sample, both by itself and in a THRESHOLD
775 // a PROMPTED_PASSWORD sample
776 promptCred.sample(0) = TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT);
777 promptCred.sample(1) = TypedList(alloc, CSSM_SAMPLE_TYPE_THRESHOLD,
778 new(alloc) ListElement(TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT)));
779 promptCred.sample(2) = TypedList(alloc, CSSM_SAMPLE_TYPE_PROMPTED_PASSWORD,
780 new(alloc) ListElement(alloc, CssmData()));
781
782 // This unwrap object is here just to provide a context
783 CssmClient::UnwrapKey unwrap(Server::csp(), CSSM_ALGID_NONE); //ok to lie about csp here
784 unwrap.mode(CSSM_ALGMODE_NONE);
785 unwrap.padding(CSSM_PADDING_PKCS1);
786 unwrap.cred(promptCred);
787 unwrap.add(CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT, uint32(CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7));
788 Security::Context *tmpContext;
789 CSSM_CC_HANDLE CCHandle = unwrap.handle();
790 /*CSSM_RETURN rx = */ CSSM_GetContext (CCHandle, (CSSM_CONTEXT_PTR *)&tmpContext);
791
792 // OK, this is skanky but necessary. We overwrite fields in the context struct
793
794 tmpContext->ContextType = CSSM_ALGCLASS_ASYMMETRIC;
795 tmpContext->AlgorithmType = CSSM_ALGID_RSA;
796
797 db.unwrapKey(*tmpContext, cred, owner, unwrappingKey, NULL, usage, attrs,
798 rawWrappedKey, masterKey, emptyDescriptiveData);
799
800 Allocator::standard().free(rawWrappedKey.KeyData.Data);
801
802 return safer_cast<LocalKey &>(*masterKey).key();
803 }
804 else
805 {
806 // not a KeyHandle reference; use key as a raw key
807 if (key.header().blobType() != CSSM_KEYBLOB_RAW)
808 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE);
809 if (key.header().keyClass() != CSSM_KEYCLASS_SESSION_KEY)
810 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
811 return CssmClient::Key(Server::csp(), key, true);
812 }
813 }
814
815 void unflattenKey(const CssmData &flatKey, CssmKey &rawKey)
816 {
817 // unflatten the raw input key naively: key header then key data
818 // We also convert it back to host byte order
819 // A CSSM_KEY is a CSSM_KEYHEADER followed by a CSSM_DATA
820
821 // Now copy: header, then key struct, then key data
822 memcpy(&rawKey.KeyHeader, flatKey.Data, sizeof(CSSM_KEYHEADER));
823 memcpy(&rawKey.KeyData, flatKey.Data + sizeof(CSSM_KEYHEADER), sizeof(CSSM_DATA));
824 const uint32 keyDataLength = flatKey.length() - sizeof(CSSM_KEY);
825 rawKey.KeyData.Data = Allocator::standard().malloc<uint8>(keyDataLength);
826 rawKey.KeyData.Length = keyDataLength;
827 memcpy(rawKey.KeyData.Data, flatKey.Data + sizeof(CSSM_KEY), keyDataLength);
828 Security::n2hi(rawKey.KeyHeader); // convert it to host byte order
829 }
830
831
832 //
833 // Verify a putative database passphrase.
834 // If the database is already unlocked, just check the passphrase.
835 // Otherwise, unlock with that passphrase and report success.
836 // Caller must hold the common lock.
837 //
838 bool KeychainDatabase::validatePassphrase(const CssmData &passphrase) const
839 {
840 if (common().hasMaster()) {
841 // verify against known secret
842 return common().validatePassphrase(passphrase);
843 } else {
844 // no master secret - perform "blind" unlock to avoid actual unlock
845 try {
846 DatabaseCryptoCore test;
847 test.setup(mBlob, passphrase);
848 test.decodeCore(mBlob, NULL);
849 return true;
850 } catch (...) {
851 return false;
852 }
853 }
854 }
855
856
857 //
858 // Lock this database
859 //
860 void KeychainDatabase::lockDb()
861 {
862 common().lockDb();
863 }
864
865
866 //
867 // Given a Key for this database, encode it into a blob and return it.
868 //
869 KeyBlob *KeychainDatabase::encodeKey(const CssmKey &key, const CssmData &pubAcl, const CssmData &privAcl)
870 {
871 bool inTheClear = false;
872
873 if((key.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY) &&
874 !(key.attribute(CSSM_KEYATTR_PUBLIC_KEY_ENCRYPT))) {
875 inTheClear = true;
876 }
877 if(!inTheClear) {
878 unlockDb();
879 }
880
881 // tell the cryptocore to form the key blob
882 return common().encodeKeyCore(key, pubAcl, privAcl, inTheClear);
883 }
884
885
886 //
887 // Given a "blobbed" key for this database, decode it into its real
888 // key object and (re)populate its ACL.
889 //
890 void KeychainDatabase::decodeKey(KeyBlob *blob, CssmKey &key, void * &pubAcl, void * &privAcl)
891 {
892 if(!blob->isClearText()) {
893 unlockDb(); // we need our keys
894 }
895
896 common().decodeKeyCore(blob, key, pubAcl, privAcl);
897 // memory protocol: pubAcl points into blob; privAcl was allocated
898
899 activity();
900 }
901
902 //
903 // Given a KeychainKey (that implicitly belongs to another keychain),
904 // return it encoded using this keychain's operational secrets.
905 //
906 KeyBlob *KeychainDatabase::recodeKey(KeychainKey &oldKey)
907 {
908 if (mRecodingSource != &oldKey.referent<KeychainDatabase>()) {
909 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
910 }
911 oldKey.instantiateAcl(); // make sure key is decoded
912 CssmData publicAcl, privateAcl;
913 oldKey.exportBlob(publicAcl, privateAcl);
914 // NB: blob's memory belongs to caller, not the common
915
916 /*
917 * Make sure the new key is in the same cleartext/encrypted state.
918 */
919 bool inTheClear = false;
920 assert(oldKey.blob());
921 if(oldKey.blob() && oldKey.blob()->isClearText()) {
922 /* careful....*/
923 inTheClear = true;
924 }
925 KeyBlob *blob = common().encodeKeyCore(oldKey.cssmKey(), publicAcl, privateAcl, inTheClear);
926 oldKey.acl().allocator.free(publicAcl);
927 oldKey.acl().allocator.free(privateAcl);
928 return blob;
929 }
930
931
932 //
933 // Modify database parameters
934 //
935 void KeychainDatabase::setParameters(const DBParameters &params)
936 {
937 StLock<Mutex> _(common());
938 makeUnlocked();
939 common().mParams = params;
940 common().invalidateBlob(); // invalidate old blobs
941 activity(); // (also resets the timeout timer)
942 secdebug("KCdb", "%p common %p(%s) set params=(%u,%u)",
943 this, &common(), dbName(), params.idleTimeout, params.lockOnSleep);
944 }
945
946
947 //
948 // Retrieve database parameters
949 //
950 void KeychainDatabase::getParameters(DBParameters &params)
951 {
952 StLock<Mutex> _(common());
953 makeUnlocked();
954 params = common().mParams;
955 //activity(); // getting parameters does not reset the idle timer
956 }
957
958
959 //
960 // RIGHT NOW, database ACLs are attached to the database.
961 // This will soon move upstairs.
962 //
963 SecurityServerAcl &KeychainDatabase::acl()
964 {
965 return *this;
966 }
967
968
969 //
970 // Intercept ACL change requests and reset blob validity
971 //
972 void KeychainDatabase::instantiateAcl()
973 {
974 StLock<Mutex> _(common());
975 makeUnlocked();
976 }
977
978 void KeychainDatabase::changedAcl()
979 {
980 StLock<Mutex> _(common());
981 version = 0;
982 }
983
984
985 //
986 // Check an incoming DbBlob for basic viability
987 //
988 void KeychainDatabase::validateBlob(const DbBlob *blob)
989 {
990 // perform basic validation on the blob
991 assert(blob);
992 blob->validate(CSSMERR_APPLEDL_INVALID_DATABASE_BLOB);
993 switch (blob->version()) {
994 #if defined(COMPAT_OSX_10_0)
995 case DbBlob::version_MacOS_10_0:
996 break;
997 #endif
998 case DbBlob::version_MacOS_10_1:
999 break;
1000 default:
1001 CssmError::throwMe(CSSMERR_APPLEDL_INCOMPATIBLE_DATABASE_BLOB);
1002 }
1003 }
1004
1005
1006 //
1007 // Debugging support
1008 //
1009 #if defined(DEBUGDUMP)
1010
1011 void KeychainDbCommon::dumpNode()
1012 {
1013 PerSession::dumpNode();
1014 uint32 sig; memcpy(&sig, &mIdentifier.signature(), sizeof(sig));
1015 Debug::dump(" %s[%8.8x]", mIdentifier.dbName(), sig);
1016 if (isLocked()) {
1017 Debug::dump(" locked");
1018 } else {
1019 time_t whenTime = time_t(when());
1020 Debug::dump(" unlocked(%24.24s/%.2g)", ctime(&whenTime),
1021 (when() - Time::now()).seconds());
1022 }
1023 Debug::dump(" params=(%u,%u)", mParams.idleTimeout, mParams.lockOnSleep);
1024 }
1025
1026 void KeychainDatabase::dumpNode()
1027 {
1028 PerProcess::dumpNode();
1029 Debug::dump(" %s vers=%u",
1030 mValidData ? " data" : " nodata", version);
1031 if (mBlob) {
1032 uint32 sig; memcpy(&sig, &mBlob->randomSignature, sizeof(sig));
1033 Debug::dump(" blob=%p[%8.8x]", mBlob, sig);
1034 } else {
1035 Debug::dump(" noblob");
1036 }
1037 }
1038
1039 #endif //DEBUGDUMP
1040
1041
1042 //
1043 // DbCommon basic features
1044 //
1045 KeychainDbCommon::KeychainDbCommon(Session &ssn, const DbIdentifier &id)
1046 : LocalDbCommon(ssn), sequence(0), version(1), mIdentifier(id),
1047 mIsLocked(true), mValidParams(false)
1048 {
1049 // match existing DbGlobal or create a new one
1050 Server &server = Server::active();
1051 StLock<Mutex> _(server);
1052 if (KeychainDbGlobal *dbglobal =
1053 server.findFirst<KeychainDbGlobal, const DbIdentifier &>(&KeychainDbGlobal::identifier, identifier())) {
1054 parent(*dbglobal);
1055 secdebug("KCdb", "%p linking to existing DbGlobal %p", this, dbglobal);
1056 } else {
1057 // DbGlobal not present; make a new one
1058 parent(*new KeychainDbGlobal(identifier()));
1059 secdebug("KCdb", "%p linking to new DbGlobal %p", this, &global());
1060 }
1061
1062 // link lifetime to the Session
1063 session().addReference(*this);
1064 }
1065
1066 KeychainDbCommon::~KeychainDbCommon()
1067 {
1068 secdebug("KCdb", "DbCommon %p destroyed", this);
1069
1070 // explicitly unschedule ourselves
1071 Server::active().clearTimer(this);
1072 }
1073
1074 KeychainDbGlobal &KeychainDbCommon::global() const
1075 {
1076 return parent<KeychainDbGlobal>();
1077 }
1078
1079
1080 void KeychainDbCommon::select()
1081 { this->ref(); }
1082
1083 void KeychainDbCommon::unselect()
1084 { this->unref(); }
1085
1086
1087
1088 void KeychainDbCommon::makeNewSecrets()
1089 {
1090 // we already have a master key (right?)
1091 assert(hasMaster());
1092
1093 // tell crypto core to generate the use keys
1094 DatabaseCryptoCore::generateNewSecrets();
1095
1096 // we're now officially "unlocked"; set the timer
1097 setUnlocked();
1098 }
1099
1100
1101 //
1102 // All unlocking activity ultimately funnels through this method.
1103 // This unlocks a DbCommon using the secrets setup in its crypto core
1104 // component, and performs all the housekeeping needed to represent
1105 // the state change.
1106 // Returns true if unlock was successful, false if it failed due to
1107 // invalid/insufficient secrets. Throws on other errors.
1108 //
1109 bool KeychainDbCommon::unlockDb(DbBlob *blob, void **privateAclBlob)
1110 {
1111 try {
1112 // Tell the cryptocore to (try to) decode itself. This will fail
1113 // in an astonishing variety of ways if the passphrase is wrong.
1114 assert(hasMaster());
1115 decodeCore(blob, privateAclBlob);
1116 secdebug("KCdb", "%p unlock successful", this);
1117 } catch (...) {
1118 secdebug("KCdb", "%p unlock failed", this);
1119 return false;
1120 }
1121
1122 // get the database parameters only if we haven't got them yet
1123 if (!mValidParams) {
1124 mParams = blob->params;
1125 n2hi(mParams.idleTimeout);
1126 mValidParams = true; // sticky
1127 }
1128
1129 bool isLocked = mIsLocked;
1130
1131 setUnlocked(); // mark unlocked
1132
1133 if (isLocked) {
1134 // broadcast unlock notification, but only if we were previously locked
1135 notify(kNotificationEventUnlocked);
1136 }
1137 return true;
1138 }
1139
1140 void KeychainDbCommon::setUnlocked()
1141 {
1142 session().addReference(*this); // active/held
1143 mIsLocked = false; // mark unlocked
1144 activity(); // set timeout timer
1145 }
1146
1147
1148 void KeychainDbCommon::lockDb()
1149 {
1150 StLock<Mutex> _(*this);
1151 if (!isLocked()) {
1152 secdebug("KCdb", "common %s(%p) locking", dbName(), this);
1153 DatabaseCryptoCore::invalidate();
1154 notify(kNotificationEventLocked);
1155 Server::active().clearTimer(this);
1156
1157 mIsLocked = true; // mark locked
1158
1159 // this call may destroy us if we have no databases anymore
1160 session().removeReference(*this);
1161 }
1162 }
1163
1164
1165 DbBlob *KeychainDbCommon::encode(KeychainDatabase &db)
1166 {
1167 assert(!isLocked()); // must have been unlocked by caller
1168
1169 // export database ACL to blob form
1170 CssmData pubAcl, privAcl;
1171 db.acl().exportBlob(pubAcl, privAcl);
1172
1173 // tell the cryptocore to form the blob
1174 DbBlob form;
1175 form.randomSignature = identifier();
1176 form.sequence = sequence;
1177 form.params = mParams;
1178 h2ni(form.params.idleTimeout);
1179
1180 assert(hasMaster());
1181 DbBlob *blob = encodeCore(form, pubAcl, privAcl);
1182
1183 // clean up and go
1184 db.acl().allocator.free(pubAcl);
1185 db.acl().allocator.free(privAcl);
1186 return blob;
1187 }
1188
1189
1190 //
1191 // Perform deferred lock processing for a database.
1192 //
1193 void KeychainDbCommon::action()
1194 {
1195 secdebug("KCdb", "common %s(%p) locked by timer", dbName(), this);
1196 lockDb();
1197 }
1198
1199 void KeychainDbCommon::activity()
1200 {
1201 if (!isLocked()) {
1202 secdebug("KCdb", "setting DbCommon %p timer to %d",
1203 this, int(mParams.idleTimeout));
1204 Server::active().setTimer(this, Time::Interval(int(mParams.idleTimeout)));
1205 }
1206 }
1207
1208 void KeychainDbCommon::sleepProcessing()
1209 {
1210 secdebug("KCdb", "common %s(%p) sleep-lock processing", dbName(), this);
1211 StLock<Mutex> _(*this);
1212 if (mParams.lockOnSleep)
1213 lockDb();
1214 }
1215
1216 void KeychainDbCommon::lockProcessing()
1217 {
1218 lockDb();
1219 }
1220
1221
1222 //
1223 // Keychain global objects
1224 //
1225 KeychainDbGlobal::KeychainDbGlobal(const DbIdentifier &id)
1226 : mIdentifier(id)
1227 {
1228 }
1229
1230 KeychainDbGlobal::~KeychainDbGlobal()
1231 {
1232 secdebug("KCdb", "DbGlobal %p destroyed", this);
1233 }