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