]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_keychain/lib/Item.cpp
Security-57337.50.23.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / lib / Item.cpp
1 /*
2 * Copyright (c) 2000-2004,2011-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 // Item.cpp
27 //
28
29 #include "Item.h"
30
31 #include "Certificate.h"
32 #include "KeyItem.h"
33 #include "ExtendedAttribute.h"
34
35 #include "Globals.h"
36 #include <security_cdsa_utilities/Schema.h>
37 #include "KCEventNotifier.h"
38 #include "KCExceptions.h"
39 #include "cssmdatetime.h"
40 #include <security_cdsa_client/keychainacl.h>
41 #include <security_utilities/osxcode.h>
42 #include <security_utilities/trackingallocator.h>
43 #include <Security/SecKeychainItemPriv.h>
44 #include <Security/cssmapple.h>
45 #include <CommonCrypto/CommonDigest.h>
46 #include <utilities/der_plist.h>
47
48 #include <security_utilities/CSPDLTransaction.h>
49 #include <SecBasePriv.h>
50
51 #define SENDACCESSNOTIFICATIONS 1
52
53 //%%% schema indexes should be defined in Schema.h
54 #define _kSecAppleSharePasswordItemClass 'ashp'
55 #define APPLEDB_CSSM_PRINTNAME_ATTRIBUTE 1 /* schema index for label attribute of keys or certificates */
56 #define APPLEDB_GENERIC_PRINTNAME_ATTRIBUTE 7 /* schema index for label attribute of password items */
57 #define IS_PASSWORD_ITEM_CLASS(X) ( (X) == kSecInternetPasswordItemClass || \
58 (X) == kSecGenericPasswordItemClass || \
59 (X) == _kSecAppleSharePasswordItemClass ) ? 1 : 0
60
61 using namespace KeychainCore;
62 using namespace CSSMDateTimeUtils;
63
64 //
65 // ItemImpl
66 //
67
68 // NewItemImpl constructor
69 ItemImpl::ItemImpl(SecItemClass itemClass, OSType itemCreator, UInt32 length, const void* data, bool dontDoAttributes)
70 : mDbAttributes(new DbAttributes()),
71 mKeychain(NULL),
72 secd_PersistentRef(NULL),
73 mDoNotEncrypt(false),
74 mInCache(false),
75 mMutex(Mutex::recursive)
76 {
77 if (length && data)
78 mData = new CssmDataContainer(data, length);
79
80 mDbAttributes->recordType(Schema::recordTypeFor(itemClass));
81
82 if (itemCreator)
83 mDbAttributes->add(Schema::attributeInfo(kSecCreatorItemAttr), itemCreator);
84 }
85
86 ItemImpl::ItemImpl(SecItemClass itemClass, SecKeychainAttributeList *attrList, UInt32 length, const void* data)
87 : mDbAttributes(new DbAttributes()),
88 mKeychain(NULL),
89 secd_PersistentRef(NULL),
90 mDoNotEncrypt(false),
91 mInCache(false),
92 mMutex(Mutex::recursive)
93 {
94 if (length && data)
95 mData = new CssmDataContainer(data, length);
96
97
98 mDbAttributes->recordType(Schema::recordTypeFor(itemClass));
99
100 if(attrList)
101 {
102 for(UInt32 i=0; i < attrList->count; i++)
103 {
104 mDbAttributes->add(Schema::attributeInfo(attrList->attr[i].tag), CssmData(attrList->attr[i].data, attrList->attr[i].length));
105 }
106 }
107 }
108
109 // DbItemImpl constructor
110 ItemImpl::ItemImpl(const Keychain &keychain, const PrimaryKey &primaryKey, const DbUniqueRecord &uniqueId)
111 : mUniqueId(uniqueId), mKeychain(keychain), mPrimaryKey(primaryKey),
112 secd_PersistentRef(NULL), mDoNotEncrypt(false), mInCache(false),
113 mMutex(Mutex::recursive)
114 {
115 }
116
117 // PrimaryKey ItemImpl constructor
118 ItemImpl::ItemImpl(const Keychain &keychain, const PrimaryKey &primaryKey)
119 : mKeychain(keychain), mPrimaryKey(primaryKey), secd_PersistentRef(NULL), mDoNotEncrypt(false),
120 mInCache(false),
121 mMutex(Mutex::recursive)
122 {
123 }
124
125 ItemImpl* ItemImpl::make(const Keychain &keychain, const PrimaryKey &primaryKey, const CssmClient::DbUniqueRecord &uniqueId)
126 {
127 ItemImpl* ii = new ItemImpl(keychain, primaryKey, uniqueId);
128 keychain->addItem(primaryKey, ii);
129 return ii;
130 }
131
132
133
134 ItemImpl* ItemImpl::make(const Keychain &keychain, const PrimaryKey &primaryKey)
135 {
136 ItemImpl* ii = new ItemImpl(keychain, primaryKey);
137 keychain->addItem(primaryKey, ii);
138 return ii;
139 }
140
141
142
143 // Constructor used when copying an item to a keychain.
144
145 ItemImpl::ItemImpl(ItemImpl &item) :
146 mData(item.modifiedData() ? NULL : new CssmDataContainer()),
147 mDbAttributes(new DbAttributes()),
148 mKeychain(NULL),
149 secd_PersistentRef(NULL),
150 mDoNotEncrypt(false),
151 mInCache(false),
152 mMutex(Mutex::recursive)
153 {
154 mDbAttributes->recordType(item.recordType());
155
156 if (item.mKeychain) {
157 // get the entire source item from its keychain. This requires figuring
158 // out the schema for the item based on its record type.
159 fillDbAttributesFromSchema(*mDbAttributes, item.recordType());
160
161 item.getContent(mDbAttributes.get(), mData.get());
162 }
163
164 // @@@ We don't deal with modified attributes.
165
166 if (item.modifiedData())
167 // the copied data comes from the source item
168 mData = new CssmDataContainer(item.modifiedData()->Data,
169 item.modifiedData()->Length);
170 }
171
172 ItemImpl::~ItemImpl()
173 {
174 if (secd_PersistentRef) {
175 CFRelease(secd_PersistentRef);
176 }
177 }
178
179
180
181 Mutex*
182 ItemImpl::getMutexForObject()
183 {
184 if (mKeychain.get())
185 {
186 return mKeychain->getKeychainMutex();
187 }
188
189 return NULL;
190 }
191
192
193 void
194 ItemImpl::aboutToDestruct()
195 {
196 if(mKeychain.get()) {
197 mKeychain->forceRemoveFromCache(this);
198 }
199 }
200
201
202
203 void
204 ItemImpl::didModify()
205 {
206 StLock<Mutex>_(mMutex);
207 mData = NULL;
208 mDbAttributes.reset(NULL);
209 }
210
211 const CSSM_DATA &
212 ItemImpl::defaultAttributeValue(const CSSM_DB_ATTRIBUTE_INFO &info)
213 {
214 static const uint32 zeroInt = 0;
215 static const double zeroDouble = 0.0;
216 static const char timeBytes[] = "20010101000000Z";
217
218 static const CSSM_DATA defaultFourBytes = { 4, (uint8 *) &zeroInt };
219 static const CSSM_DATA defaultEightBytes = { 8, (uint8 *) &zeroDouble };
220 static const CSSM_DATA defaultTime = { 16, (uint8 *) timeBytes };
221 static const CSSM_DATA defaultZeroBytes = { 0, NULL };
222
223 switch (info.AttributeFormat)
224 {
225 case CSSM_DB_ATTRIBUTE_FORMAT_SINT32:
226 case CSSM_DB_ATTRIBUTE_FORMAT_UINT32:
227 return defaultFourBytes;
228
229 case CSSM_DB_ATTRIBUTE_FORMAT_REAL:
230 return defaultEightBytes;
231
232 case CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE:
233 return defaultTime;
234
235 default:
236 return defaultZeroBytes;
237 }
238 }
239
240 void ItemImpl::fillDbAttributesFromSchema(DbAttributes& dbAttributes, CSSM_DB_RECORDTYPE recordType, Keychain keychain) {
241 // If we weren't passed a keychain, use our own.
242 keychain = !!keychain ? keychain : mKeychain;
243
244 // Without a keychain, there's no one to ask.
245 if(!keychain) {
246 return;
247 }
248
249 SecKeychainAttributeInfo* infos;
250 keychain->getAttributeInfoForItemID(recordType, &infos);
251
252 secdebugfunc("integrity", "filling %u attributes for type %u", (unsigned int)infos->count, recordType);
253
254 for (uint32 i = 0; i < infos->count; i++) {
255 CSSM_DB_ATTRIBUTE_INFO info;
256 memset(&info, 0, sizeof(info));
257
258 info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER;
259 info.Label.AttributeID = infos->tag[i];
260 info.AttributeFormat = infos->format[i];
261
262 dbAttributes.add(info);
263 }
264
265 keychain->freeAttributeInfo(infos);
266 }
267
268 DbAttributes* ItemImpl::getCurrentAttributes() {
269 DbAttributes* dbAttributes;
270 secdebugfunc("integrity", "getting current attributes...");
271
272 if(mUniqueId.get()) {
273 // If we have a unique id, there's an item in the database backing us. Ask for its attributes.
274 dbAttributes = new DbAttributes(mUniqueId->database(), 1);
275 fillDbAttributesFromSchema(*dbAttributes, recordType());
276 mUniqueId->get(dbAttributes, NULL);
277
278 // and fold in any updates.
279 if(mDbAttributes.get()) {
280 secdebugfunc("integrity", "adding %d attributes from mDbAttributes", mDbAttributes->size());
281 dbAttributes->updateWithDbAttributes(&(*mDbAttributes.get()));
282 }
283 } else if (mDbAttributes.get()) {
284 // We don't have a backing item, so all our attributes are in mDbAttributes. Copy them.
285 secdebugfunc("integrity", "no unique id, using %d attributes from mDbAttributes", mDbAttributes->size());
286 dbAttributes = new DbAttributes();
287 dbAttributes->updateWithDbAttributes(&(*mDbAttributes.get()));
288 } else {
289 // No attributes at all. We should maybe throw here, but let's not.
290 secdebugfunc("integrity", "no attributes at all");
291 dbAttributes = new DbAttributes();
292 }
293 dbAttributes->recordType(recordType());
294 // TODO: We don't set semanticInformation. Issue?
295
296 return dbAttributes;
297 }
298
299
300 void ItemImpl::encodeAttributes(CssmOwnedData &attributeBlob) {
301 // Sometimes we don't have our attributes. Find them.
302 auto_ptr<DbAttributes> dbAttributes(getCurrentAttributes());
303 encodeAttributesFromDictionary(attributeBlob, dbAttributes.get());
304
305 }
306
307 void ItemImpl::encodeAttributesFromDictionary(CssmOwnedData &attributeBlob, DbAttributes* dbAttributes) {
308 // Create a CFDictionary from dbAttributes and call der_encode_dictionary on it
309 CFRef<CFMutableDictionaryRef> attributes;
310 attributes.take(CFDictionaryCreateMutable(NULL, dbAttributes->size(), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
311
312 secdebugfunc("integrity", "looking at %d attributes", dbAttributes->size());
313 // TODO: include record type and semantic information?
314
315 for(int i = 0; i < dbAttributes->size(); i++) {
316 CssmDbAttributeData& data = dbAttributes->attributes()[i];
317 CssmDbAttributeInfo& datainfo = data.info();
318
319 // Sometimes we need to normalize the info. Calling Schema::attributeInfo is the best way to do that.
320 // There's no avoiding the try-catch structure here, since only some of the names are in Schema::attributeInfo,
321 // but it will only indicate that by throwing.
322 CssmDbAttributeInfo& actualInfo = datainfo;
323 try {
324 if(datainfo.nameFormat() == CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER && Schema::haveAttributeInfo(datainfo.intName())) {
325 actualInfo = Schema::attributeInfo(datainfo.intName());
326 }
327 } catch(...) {
328 actualInfo = datainfo;
329 }
330
331 // Pull the label/name out of this data
332 CFRef<CFDataRef> label = NULL;
333
334 switch(actualInfo.nameFormat()) {
335 case CSSM_DB_ATTRIBUTE_NAME_AS_STRING: {
336 const char* stringname = actualInfo.stringName();
337 label.take(CFDataCreate(NULL, reinterpret_cast<const UInt8*>(stringname), strlen(stringname)));
338 break;
339 }
340 case CSSM_DB_ATTRIBUTE_NAME_AS_OID: {
341 const CssmOid& oidname = actualInfo.oidName();
342 label.take(CFDataCreate(NULL, reinterpret_cast<const UInt8*>(oidname.data()), oidname.length()));
343 break;
344 }
345 case CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER: {
346 uint32 iname = actualInfo.intName();
347 label.take(CFDataCreate(NULL, reinterpret_cast<const UInt8*>(&(iname)), sizeof(uint32)));
348 break;
349 }
350 }
351
352 if(data.size() == 0) {
353 // This attribute doesn't have a value, and so shouldn't be included in the digest.
354 continue;
355 }
356
357 // Do not include the Creation or Modification date attributes in the hash.
358 // Use this complicated method of checking so we'll catch string and integer names.
359 SecKeychainAttrType cdat = kSecCreationDateItemAttr;
360 SecKeychainAttrType cmod = kSecModDateItemAttr;
361 if((CFDataGetLength(label) == sizeof(SecKeychainAttrType)) &&
362 ((memcmp(CFDataGetBytePtr(label), &cdat, sizeof(SecKeychainAttrType)) == 0) ||
363 (memcmp(CFDataGetBytePtr(label), &cmod, sizeof(SecKeychainAttrType)) == 0))) {
364 continue;
365 }
366
367 // Collect the raw data for each value of this CssmDbAttributeData
368 CFRef<CFMutableArrayRef> attributeDataContainer;
369 attributeDataContainer.take(CFArrayCreateMutable(NULL, data.size(), &kCFTypeArrayCallBacks));
370
371 for(int j = 0; j < data.size(); j++) {
372 CssmData& entry = data.values()[j];
373
374 CFRef<CFDataRef> datadata = NULL;
375 switch(actualInfo.format()) {
376 case CSSM_DB_ATTRIBUTE_FORMAT_BLOB:
377 case CSSM_DB_ATTRIBUTE_FORMAT_STRING:
378 case CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE:
379 datadata.take(CFDataCreate(NULL, reinterpret_cast<const UInt8*>(data.values()[j].data()), data.values()[j].length()));
380 break;
381
382 case CSSM_DB_ATTRIBUTE_FORMAT_UINT32: {
383 uint32 x = entry.length() == 1 ? *reinterpret_cast<uint8 *>(entry.Data) :
384 entry.length() == 2 ? *reinterpret_cast<uint16 *>(entry.Data) :
385 entry.length() == 4 ? *reinterpret_cast<uint32 *>(entry.Data) : 0;
386 datadata.take(CFDataCreate(NULL, reinterpret_cast<const UInt8*>(&x), sizeof(x)));
387 break;
388 }
389
390 case CSSM_DB_ATTRIBUTE_FORMAT_SINT32: {
391 sint32 x = entry.length() == 1 ? *reinterpret_cast<sint8 *>(entry.Data) :
392 entry.length() == 2 ? *reinterpret_cast<sint16 *>(entry.Data) :
393 entry.length() == 4 ? *reinterpret_cast<sint32 *>(entry.Data) : 0;
394 datadata.take(CFDataCreate(NULL, reinterpret_cast<const UInt8*>(&x), sizeof(x)));
395 break;
396 }
397 // CSSM_DB_ATTRIBUTE_FORMAT_BIG_NUM is unimplemented here but
398 // has some canonicalization requirements, see DbValue.cpp
399
400 default:
401 continue;
402 }
403
404 CFArrayAppendValue(attributeDataContainer, datadata);
405 }
406 CFDictionaryAddValue(attributes, label, attributeDataContainer);
407 }
408
409 // Now that we have a CFDictionary containing a bunch of CFDatas, turn that
410 // into a der blob.
411
412 CFErrorRef error;
413 CFRef<CFDataRef> derBlob;
414 derBlob.take(CFPropertyListCreateDERData(NULL, attributes, &error));
415
416 // TODO: How do we check error here?
417
418 if(!derBlob) {
419 return;
420 }
421
422 attributeBlob.length(CFDataGetLength(derBlob));
423 attributeBlob.copy(CFDataGetBytePtr(derBlob), CFDataGetLength(derBlob));
424 }
425
426 void ItemImpl::computeDigest(CssmOwnedData &sha2) {
427 auto_ptr<DbAttributes> dbAttributes(getCurrentAttributes());
428 ItemImpl::computeDigestFromDictionary(sha2, dbAttributes.get());
429 }
430
431 void ItemImpl::computeDigestFromDictionary(CssmOwnedData &sha2, DbAttributes* dbAttributes) {
432 try{
433 CssmAutoData attributeBlob(Allocator::standard());
434 encodeAttributesFromDictionary(attributeBlob, dbAttributes);
435
436 sha2.length(CC_SHA256_DIGEST_LENGTH);
437 CC_SHA256(attributeBlob.get().data(), static_cast<CC_LONG>(attributeBlob.get().length()), sha2);
438 secdebugfunc("integrity", "finished: %s", sha2.get().toHex().c_str());
439 } catch (MacOSError mose) {
440 secdebugfunc("integrity", "MacOSError: %d", (int)mose.osStatus());
441 } catch (...) {
442 secdebugfunc("integrity", "unknown exception");
443 }
444 }
445
446 void ItemImpl::addIntegrity(Access &access, bool force) {
447 secdebugfunc("integrity", "called");
448
449 if(!force && (!mKeychain || !mKeychain->hasIntegrityProtection())) {
450 secdebugfunc("integrity", "skipping integrity add due to keychain version\n");
451 return;
452 }
453
454 ACL * acl = NULL;
455 CssmAutoData digest(Allocator::standard());
456 computeDigest(digest);
457
458 // First, check if this already has an integrity tag
459 vector<ACL *> acls;
460 access.findSpecificAclsForRight(CSSM_ACL_AUTHORIZATION_INTEGRITY, acls);
461
462 if(acls.size() >= 1) {
463 // Use the existing ACL
464 acl = acls[0];
465 secdebugfunc("integrity", "previous integrity acl exists; setting integrity");
466 acl->setIntegrity(digest.get());
467
468 // Delete all extra ACLs
469 for(int i = 1; i < acls.size(); i++) {
470 secdebugfunc("integrity", "extra integrity acls exist; removing %d",i);
471 acls[i]->remove();
472 }
473 } else if(acls.size() == 0) {
474 // Make a new ACL
475 secdebugfunc("integrity", "no previous integrity acl exists; making a new one");
476 acl = new ACL(digest.get());
477 access.add(acl);
478 }
479 }
480
481 void ItemImpl::setIntegrity(bool force) {
482 if(!force && (!mKeychain || !mKeychain->hasIntegrityProtection())) {
483 secdebugfunc("integrity", "skipping integrity set due to keychain version");
484 return;
485 }
486
487 // For Items, only passwords should have integrity
488 if(!(recordType() == CSSM_DL_DB_RECORD_GENERIC_PASSWORD || recordType() == CSSM_DL_DB_RECORD_INTERNET_PASSWORD)) {
489 return;
490 }
491
492 // If we're not on an SSDb, we shouldn't have integrity
493 Db db(mKeychain->database());
494 if (!useSecureStorage(db)) {
495 return;
496 }
497
498 setIntegrity(*group(), force);
499 }
500
501 void ItemImpl::setIntegrity(AclBearer &bearer, bool force) {
502 if(!force && (!mKeychain || !mKeychain->hasIntegrityProtection())) {
503 secdebugfunc("integrity", "skipping integrity acl set due to keychain version");
504 return;
505 }
506
507 SecPointer<Access> access = new Access(bearer);
508
509 access->removeAclsForRight(CSSM_ACL_AUTHORIZATION_PARTITION_ID);
510 addIntegrity(*access, force);
511 access->setAccess(bearer, true);
512 }
513
514 bool ItemImpl::checkIntegrity() {
515 // Note: subclasses are responsible for checking themselves.
516
517 // If we don't have a keychain yet, we don't have any group. Return true?
518 if(!isPersistent()) {
519 secdebugfunc("integrity", "no keychain, integrity is valid?");
520 return true;
521 }
522
523 if(!mKeychain || !mKeychain->hasIntegrityProtection()) {
524 secdebugfunc("integrity", "skipping integrity check due to keychain version");
525 return true;
526 }
527
528 // Collect our SSGroup, if it exists.
529 dbUniqueRecord();
530 SSGroup ssGroup = group();
531 if(ssGroup) {
532 return checkIntegrity(*ssGroup);
533 }
534
535 // If we don't have an SSGroup, we can't be invalid. return true.
536 return true;
537 }
538
539 bool ItemImpl::checkIntegrity(AclBearer& aclBearer) {
540 if(!mKeychain || !mKeychain->hasIntegrityProtection()) {
541 secdebugfunc("integrity", "skipping integrity check due to keychain version");
542 return true;
543 }
544
545 auto_ptr<DbAttributes> dbAttributes(getCurrentAttributes());
546 return checkIntegrityFromDictionary(aclBearer, dbAttributes.get());
547 }
548
549 bool ItemImpl::checkIntegrityFromDictionary(AclBearer& aclBearer, DbAttributes* dbAttributes) {
550 try {
551 AutoAclEntryInfoList aclInfos;
552 aclBearer.getAcl(aclInfos, CSSM_APPLE_ACL_TAG_INTEGRITY);
553
554 // We should only expect there to be one integrity tag. If there's not,
555 // take the first one and ignore the rest. We should probably attempt delete
556 // them.
557
558 AclEntryInfo &info = aclInfos.at(0);
559 auto_ptr<ACL> acl(new ACL(info, Allocator::standard()));
560
561 for(int i = 1; i < aclInfos.count(); i++) {
562 secdebugfunc("integrity", "*** DUPLICATE INTEGRITY ACL, something has gone wrong");
563 }
564
565 CssmAutoData digest(Allocator::standard());
566 computeDigestFromDictionary(digest, dbAttributes);
567 if (acl->integrity() == digest.get()) {
568 return true;
569 }
570 }
571 catch (CssmError cssme) {
572 const char* errStr = cssmErrorString(cssme.error);
573 secdebugfunc("integrity", "caught CssmError: %d %s", (int) cssme.error, errStr);
574
575 if(cssme.error == CSSMERR_CSP_ACL_ENTRY_TAG_NOT_FOUND) {
576 // TODO: No entry, run migrator?
577 return true;
578 }
579 if(cssme.error == CSSMERR_CSP_INVALID_ACL_SUBJECT_VALUE) {
580 // something went horribly wrong with fetching acl.
581
582 secdebugfunc("integrity", "INVALID ITEM (too many integrity acls)");
583 return false;
584 }
585 if(cssme.error == CSSMERR_CSP_VERIFY_FAILED) {
586 secdebugfunc("integrity", "MAC verification failed; something has gone very wrong");
587 }
588
589 throw cssme;
590 }
591
592 secdebugfunc("integrity", "***** INVALID ITEM");
593 return false;
594 }
595
596 PrimaryKey ItemImpl::addWithCopyInfo (Keychain &keychain, bool isCopy)
597 {
598 StLock<Mutex>_(mMutex);
599 // If we already have a Keychain we can't be added.
600 if (mKeychain)
601 MacOSError::throwMe(errSecDuplicateItem);
602
603 // If we don't have any attributes we can't be added.
604 // (this might occur if attempting to add the item twice, since our attributes
605 // and data are set to NULL at the end of this function.)
606 if (!mDbAttributes.get())
607 MacOSError::throwMe(errSecDuplicateItem);
608
609 CSSM_DB_RECORDTYPE recordType = mDbAttributes->recordType();
610
611 // update the creation and update dates on the new item
612 if (!isCopy)
613 {
614 KeychainSchema schema = keychain->keychainSchema();
615 SInt64 date;
616 GetCurrentMacLongDateTime(date);
617 if (schema->hasAttribute(recordType, kSecCreationDateItemAttr))
618 {
619 setAttribute(schema->attributeInfoFor(recordType, kSecCreationDateItemAttr), date);
620 }
621
622 if (schema->hasAttribute(recordType, kSecModDateItemAttr))
623 {
624 setAttribute(schema->attributeInfoFor(recordType, kSecModDateItemAttr), date);
625 }
626 }
627
628 // If the label (PrintName) attribute isn't specified, set a default label.
629 if (!mDoNotEncrypt && !mDbAttributes->find(Schema::attributeInfo(kSecLabelItemAttr)))
630 {
631 // if doNotEncrypt was set all of the attributes are wrapped in the data blob. Don't calculate here.
632 CssmDbAttributeData *label = NULL;
633 switch (recordType)
634 {
635 case CSSM_DL_DB_RECORD_GENERIC_PASSWORD:
636 label = mDbAttributes->find(Schema::attributeInfo(kSecServiceItemAttr));
637 break;
638
639 case CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD:
640 case CSSM_DL_DB_RECORD_INTERNET_PASSWORD:
641 label = mDbAttributes->find(Schema::attributeInfo(kSecServerItemAttr));
642 // if AppleShare server name wasn't specified, try the server address
643 if (!label) label = mDbAttributes->find(Schema::attributeInfo(kSecAddressItemAttr));
644 break;
645
646 default:
647 break;
648 }
649 // if all else fails, use the account name.
650 if (!label)
651 label = mDbAttributes->find(Schema::attributeInfo(kSecAccountItemAttr));
652
653 if (label && label->size())
654 setAttribute (Schema::attributeInfo(kSecLabelItemAttr), label->at<CssmData>(0));
655 }
656
657 // get the attributes that are part of the primary key
658 const CssmAutoDbRecordAttributeInfo &primaryKeyInfos =
659 keychain->primaryKeyInfosFor(recordType);
660
661 // make sure each primary key element has a value in the item, otherwise
662 // the database will complain. we make a set of the provided attribute infos
663 // to avoid O(N^2) behavior.
664
665 DbAttributes *attributes = mDbAttributes.get();
666 typedef set<CssmDbAttributeInfo> InfoSet;
667 InfoSet infoSet;
668
669 if (!mDoNotEncrypt)
670 {
671 // make a set of all the attributes in the key
672 for (uint32 i = 0; i < attributes->size(); i++)
673 infoSet.insert(attributes->at(i).Info);
674
675 for (uint32 i = 0; i < primaryKeyInfos.size(); i++) { // check to make sure all required attributes are in the key
676 InfoSet::const_iterator it = infoSet.find(primaryKeyInfos.at(i));
677
678 if (it == infoSet.end()) { // not in the key? add the default
679 // we need to add a default value to the item attributes
680 attributes->add(primaryKeyInfos.at(i), defaultAttributeValue(primaryKeyInfos.at(i)));
681 }
682 }
683 }
684
685 try {
686 mKeychain = keychain;
687
688 Db db(keychain->database());
689 if (mDoNotEncrypt)
690 {
691 mUniqueId = db->insertWithoutEncryption (recordType, NULL, mData.get());
692 }
693 else if (useSecureStorage(db))
694 {
695 updateSSGroup(db, recordType, mData.get(), keychain, mAccess);
696 mAccess = NULL; // use them and lose them - TODO: should this only be unset if there's no error in saveToNewSSGroup? Unclear.
697 }
698 else
699 {
700 // add the item to the (regular) db
701 mUniqueId = db->insert(recordType, mDbAttributes.get(), mData.get());
702 }
703
704 mPrimaryKey = keychain->makePrimaryKey(recordType, mUniqueId);
705 } catch(...) {
706 mKeychain = NULL;
707 throw;
708 }
709
710 // Forget our data and attributes.
711 mData = NULL;
712 mDbAttributes.reset(NULL);
713
714 return mPrimaryKey;
715 }
716
717
718
719 PrimaryKey
720 ItemImpl::add (Keychain &keychain)
721 {
722 return addWithCopyInfo (keychain, false);
723 }
724
725
726
727 Item
728 ItemImpl::copyTo(const Keychain &keychain, Access *newAccess)
729 {
730 StLock<Mutex>_(mMutex);
731 Item item(*this);
732 if (newAccess)
733 item->setAccess(newAccess);
734 else
735 {
736 /* Attempt to copy the access from the current item to the newly created one. */
737 SSGroup myGroup = group();
738 if (myGroup)
739 {
740 SecPointer<Access> access = new Access(*myGroup);
741 item->setAccess(access);
742 }
743 }
744
745 keychain->addCopy(item);
746 return item;
747 }
748
749 void
750 ItemImpl::update()
751 {
752 StLock<Mutex>_(mMutex);
753 if (!mKeychain)
754 MacOSError::throwMe(errSecNoSuchKeychain);
755
756 // Don't update if nothing changed.
757 if (!isModified())
758 return;
759
760 CSSM_DB_RECORDTYPE aRecordType = recordType();
761 KeychainSchema schema = mKeychain->keychainSchema();
762
763 // Update the modification date on the item if there is a mod date attribute.
764 if (schema->hasAttribute(aRecordType, kSecModDateItemAttr))
765 {
766 SInt64 date;
767 GetCurrentMacLongDateTime(date);
768 setAttribute(schema->attributeInfoFor(aRecordType, kSecModDateItemAttr), date);
769 }
770
771 // Make sure that we have mUniqueId
772 dbUniqueRecord();
773 Db db(mUniqueId->database());
774 if (mDoNotEncrypt)
775 {
776 CSSM_DB_RECORD_ATTRIBUTE_DATA attrData;
777 memset (&attrData, 0, sizeof (attrData));
778 attrData.DataRecordType = aRecordType;
779
780 mUniqueId->modifyWithoutEncryption(aRecordType,
781 &attrData,
782 mData.get(),
783 CSSM_DB_MODIFY_ATTRIBUTE_REPLACE);
784 }
785 else if (useSecureStorage(db))
786 {
787 // Pass mData to updateSSGroup. If we have any data to change (and it's
788 // therefore non-null), it'll save to a new SSGroup; otherwise, it will
789 // update the old ssgroup. This prevents a RAA on attribute update, while
790 // still protecting new data from being decrypted by old SSGroups with
791 // outdated attributes.
792 updateSSGroup(db, recordType(), mData.get());
793 }
794 else
795 {
796 mUniqueId->modify(aRecordType,
797 mDbAttributes.get(),
798 mData.get(),
799 CSSM_DB_MODIFY_ATTRIBUTE_REPLACE);
800 }
801
802 if (!mDoNotEncrypt)
803 {
804 PrimaryKey oldPK = mPrimaryKey;
805 mPrimaryKey = mKeychain->makePrimaryKey(aRecordType, mUniqueId);
806
807 // Forget our data and attributes.
808 mData = NULL;
809 mDbAttributes.reset(NULL);
810
811 // Let the Keychain update what it needs to.
812 mKeychain->didUpdate(this, oldPK, mPrimaryKey);
813 }
814 }
815
816 void
817 ItemImpl::updateSSGroup(Db& db, CSSM_DB_RECORDTYPE recordType, CssmDataContainer* newdata, Keychain keychain, SecPointer<Access> access)
818 {
819 // hhs replaced with the new aclFactory class
820 AclFactory aclFactory;
821 const AccessCredentials *nullCred = aclFactory.nullCred();
822
823 secdebugfunc("integrity", "called");
824
825 bool haveOldUniqueId = !!mUniqueId.get();
826 SSDbUniqueRecord ssUniqueId(NULL);
827 SSGroup ssGroup(NULL);
828 if(haveOldUniqueId) {
829 ssUniqueId = SSDbUniqueRecord(dynamic_cast<SSDbUniqueRecordImpl *>(&(*mUniqueId)));
830 if (ssUniqueId.get() == NULL) {
831 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER);
832 }
833 ssGroup = ssUniqueId->group();
834 }
835
836 // If we have new data OR no old unique id, save to a new group
837 bool saveToNewSSGroup = (!!newdata) || (!haveOldUniqueId);
838
839 // If there aren't any attributes, make up some blank ones.
840 if (!mDbAttributes.get())
841 {
842 secdebugfunc("integrity", "making new dbattributes");
843 mDbAttributes.reset(new DbAttributes());
844 mDbAttributes->recordType(mPrimaryKey->recordType());
845 }
846
847 // Add the item to the secure storage db
848 SSDbImpl* impl = dynamic_cast<SSDbImpl *>(&(*db));
849 if (impl == NULL)
850 {
851 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER);
852 }
853
854 SSDb ssDb(impl);
855
856 TrackingAllocator allocator(Allocator::standard());
857
858 if ((!access) && (haveOldUniqueId)) {
859 // Copy the ACL from the old group.
860 secdebugfunc("integrity", "copying old ACL");
861 access = new Access(*(ssGroup));
862
863 // We can't copy these over to the new item; they're going to be reset.
864 // Remove them before securityd complains.
865 access->removeAclsForRight(CSSM_ACL_AUTHORIZATION_PARTITION_ID);
866 access->removeAclsForRight(CSSM_ACL_AUTHORIZATION_INTEGRITY);
867 } else if (!access) {
868 secdebugfunc("integrity", "setting up new ACL");
869 // create default access controls for the new item
870 CssmDbAttributeData *data = mDbAttributes->find(Schema::attributeInfo(kSecLabelItemAttr));
871 string printName = data ? CssmData::overlay(data->Value[0]).toString() : "keychain item";
872 access = new Access(printName);
873
874 // special case for "iTools" password - allow anyone to decrypt the item
875 if (recordType == CSSM_DL_DB_RECORD_GENERIC_PASSWORD)
876 {
877 CssmDbAttributeData *data = mDbAttributes->find(Schema::attributeInfo(kSecServiceItemAttr));
878 if (data && data->Value[0].Length == 6 && !memcmp("iTools", data->Value[0].Data, 6))
879 {
880 typedef vector<SecPointer<ACL> > AclSet;
881 AclSet acls;
882 access->findAclsForRight(CSSM_ACL_AUTHORIZATION_DECRYPT, acls);
883 for (AclSet::const_iterator it = acls.begin(); it != acls.end(); it++)
884 (*it)->form(ACL::allowAllForm);
885 }
886 }
887 } else {
888 secdebugfunc("integrity", "passed an Access, use it");
889 // Access is non-null. Do nothing.
890 }
891
892 // If we have an old group and an old mUniqueId, then we're in the middle of an update.
893 // mDbAttributes contains the newest attributes, but not the old ones. Find
894 // them, merge them, and shove them all back into mDbAttributes. This lets
895 // us re-apply them all to the new item.
896 if(haveOldUniqueId) {
897 mDbAttributes.reset(getCurrentAttributes());
898 }
899
900 // Create a CSPDL transaction. Note that this does things when it goes out of scope.
901 CSPDLTransaction transaction(db);
902
903 Access::Maker maker;
904 ResourceControlContext prototype;
905 maker.initialOwner(prototype, nullCred);
906
907 if(saveToNewSSGroup) {
908 secdebugfunc("integrity", "saving to a new SSGroup");
909
910 // If we're updating an item, it has an old group and possibly an
911 // old mUniqueId. Delete these from the database, so we can insert
912 // new ones.
913 if(haveOldUniqueId) {
914 secdebugfunc("integrity", "deleting old mUniqueId");
915 mUniqueId->deleteRecord();
916 mUniqueId.release();
917 } else {
918 secdebugfunc("integrity", "no old mUniqueId");
919 }
920
921 // Create a new SSGroup with temporary access controls
922 SSGroup newSSGroup(ssDb, &prototype);
923 const AccessCredentials * cred = maker.cred();
924
925 try {
926 doChange(keychain, recordType, ^{
927 mUniqueId = ssDb->insert(recordType, mDbAttributes.get(),
928 newdata, newSSGroup, cred);
929 });
930
931 // now finalize the access controls on the group
932 addIntegrity(*access);
933 access->setAccess(*newSSGroup, maker);
934
935 // We have to reset this after we add the integrity, since it needs the attributes
936 mDbAttributes.reset(NULL);
937
938 transaction.success();
939 }
940 catch (CssmError cssme) {
941 const char* errStr = cssmErrorString(cssme.error);
942 secdebugfunc("integrity", "caught CssmError during add: %d %s", (int) cssme.error, errStr);
943 newSSGroup->deleteKey(nullCred);
944 throw;
945 }
946 catch (MacOSError mose) {
947 secdebugfunc("integrity", "caught MacOSError during add: %d", (int) mose.osStatus());
948 newSSGroup->deleteKey(nullCred);
949 throw;
950 }
951 catch (...)
952 {
953 secdebugfunc("integrity", "caught unknown exception during add");
954 // Delete the new SSGroup that we just created
955 newSSGroup->deleteKey(nullCred);
956 throw;
957 }
958 } else {
959 // Modify the old SSGroup
960 secdebugfunc("integrity", "modifying the existing SSGroup");
961
962 try {
963 doChange(keychain, recordType, ^{
964 assert(!newdata);
965 const AccessCredentials *autoPrompt = globals().itemCredentials();
966 ssUniqueId->modify(recordType,
967 mDbAttributes.get(),
968 newdata,
969 CSSM_DB_MODIFY_ATTRIBUTE_REPLACE,
970 autoPrompt);
971 });
972
973 // Update the integrity on the SSGroup
974 setIntegrity(*ssGroup);
975
976 // We have to reset this after we add the integrity, since it needs the attributes
977 mDbAttributes.reset(NULL);
978
979 transaction.success();
980 }
981 catch (CssmError cssme) {
982 const char* errStr = cssmErrorString(cssme.error);
983 secdebugfunc("integrity", "caught CssmError during modify: %d %s", (int) cssme.error, errStr);
984 throw;
985 }
986 catch (MacOSError mose) {
987 secdebugfunc("integrity", "caught MacOSError during modify: %d", (int) mose.osStatus());
988 throw;
989 }
990 catch (...)
991 {
992 secdebugfunc("integrity", "caught unknown exception during modify");
993 throw;
994 }
995
996 }
997 }
998
999 void
1000 ItemImpl::doChange(Keychain keychain, CSSM_DB_RECORDTYPE recordType, void (^tryChange) ())
1001 {
1002 // Insert the record using the newly created group.
1003 try {
1004 tryChange();
1005 } catch (CssmError cssme) {
1006 // If there's a "duplicate" of this item, it might be an item with corrupt/invalid attributes
1007 // Try to extract the item and check its attributes, then try again if necessary
1008 auto_ptr<CssmClient::DbAttributes> primaryKeyAttrs;
1009 if(cssme.error == CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA) {
1010 secdebugfunc("integrity", "possible duplicate, trying to delete invalid items");
1011
1012 Keychain kc = (keychain ? keychain : mKeychain);
1013 if(!kc) {
1014 secdebugfunc("integrity", "no valid keychain");
1015 }
1016
1017 // Only check for corrupt items if the keychain supports them
1018 if((!kc) || !kc->hasIntegrityProtection()) {
1019 secdebugfunc("integrity", "skipping integrity check for corrupt items due to keychain support");
1020 throw;
1021 } else {
1022 primaryKeyAttrs.reset(getCurrentAttributes());
1023 PrimaryKey pk = kc->makePrimaryKey(recordType, primaryKeyAttrs.get());
1024
1025 bool tryAgain = false;
1026
1027 // Because things are lazy, maybe our keychain has a version
1028 // of this item with different attributes. Ask it!
1029 ItemImpl* maybeItem = kc->_lookupItem(pk);
1030 if(maybeItem) {
1031 if(!maybeItem->checkIntegrity()) {
1032 Item item(maybeItem);
1033 kc->deleteItem(item);
1034 tryAgain = true;
1035 }
1036 } else {
1037 // Our keychain doesn't know about any item with this primary key, so maybe
1038 // we have a corrupt item in the database. Let's check.
1039
1040 secdebugfunc("integrity", "making a cursor from primary key");
1041 CssmClient::DbCursor cursor = pk->createCursor(kc);
1042 DbUniqueRecord uniqueId;
1043
1044 StLock<Mutex> _mutexLocker(*kc->getKeychainMutex());
1045
1046 // The item on-disk might have more or different attributes than we do, since we're
1047 // only searching via primary key. Fetch all of its attributes.
1048 auto_ptr<DbAttributes>dbDupAttributes (new DbAttributes(kc->database(), 1));
1049 fillDbAttributesFromSchema(*dbDupAttributes, recordType, kc);
1050
1051 // Occasionally this cursor won't return the item attributes (for an unknown reason).
1052 // However, we know the attributes any item with this primary key should have, so use those instead.
1053 while (cursor->next(dbDupAttributes.get(), NULL, uniqueId)) {
1054 secdebugfunc("integrity", "got an item...");
1055
1056 SSGroup group = safer_cast<SSDbUniqueRecordImpl &>(*uniqueId).group();
1057 if(!ItemImpl::checkIntegrityFromDictionary(*group, dbDupAttributes.get())) {
1058 secdebugfunc("integrity", "item is invalid! deleting...");
1059 uniqueId->deleteRecord();
1060 tryAgain = true;
1061 }
1062 }
1063 }
1064
1065 if(tryAgain) {
1066 secdebugfunc("integrity", "trying again...");
1067 tryChange();
1068 } else {
1069 // We didn't find an invalid item, the duplicate item exception is real
1070 secdebugfunc("integrity", "duplicate item exception is real; throwing it on");
1071 throw;
1072 }
1073 }
1074 } else {
1075 throw;
1076 }
1077 }
1078 }
1079
1080 void
1081 ItemImpl::getClass(SecKeychainAttribute &attr, UInt32 *actualLength)
1082 {
1083 StLock<Mutex>_(mMutex);
1084 if (actualLength)
1085 *actualLength = sizeof(SecItemClass);
1086
1087 if (attr.length < sizeof(SecItemClass))
1088 MacOSError::throwMe(errSecBufferTooSmall);
1089
1090 SecItemClass aClass = Schema::itemClassFor(recordType());
1091 memcpy(attr.data, &aClass, sizeof(SecItemClass));
1092 }
1093
1094 void
1095 ItemImpl::setAttribute(SecKeychainAttribute& attr)
1096 {
1097 StLock<Mutex>_(mMutex);
1098 setAttribute(Schema::attributeInfo(attr.tag), CssmData(attr.data, attr.length));
1099 }
1100
1101 CSSM_DB_RECORDTYPE
1102 ItemImpl::recordType()
1103 {
1104 StLock<Mutex>_(mMutex);
1105 if (mDbAttributes.get())
1106 return mDbAttributes->recordType();
1107
1108 return mPrimaryKey->recordType();
1109 }
1110
1111 const DbAttributes *
1112 ItemImpl::modifiedAttributes()
1113 {
1114 StLock<Mutex>_(mMutex);
1115 return mDbAttributes.get();
1116 }
1117
1118 const CssmData *
1119 ItemImpl::modifiedData()
1120 {
1121 StLock<Mutex>_(mMutex);
1122 return mData.get();
1123 }
1124
1125 void
1126 ItemImpl::setData(UInt32 length,const void *data)
1127 {
1128 StLock<Mutex>_(mMutex);
1129 mData = new CssmDataContainer(data, length);
1130 }
1131
1132 void
1133 ItemImpl::setAccess(Access *newAccess)
1134 {
1135 StLock<Mutex>_(mMutex);
1136 mAccess = newAccess;
1137 }
1138
1139 CssmClient::DbUniqueRecord
1140 ItemImpl::dbUniqueRecord()
1141 {
1142 StLock<Mutex>_(mMutex);
1143 if (!isPersistent()) // is there no database attached?
1144 {
1145 MacOSError::throwMe(errSecNotAvailable);
1146 }
1147
1148 if (!mUniqueId)
1149 {
1150 DbCursor cursor(mPrimaryKey->createCursor(mKeychain));
1151 if (!cursor->next(NULL, NULL, mUniqueId))
1152 MacOSError::throwMe(errSecInvalidItemRef);
1153 }
1154
1155 return mUniqueId;
1156 }
1157
1158 PrimaryKey
1159 ItemImpl::primaryKey()
1160 {
1161 return mPrimaryKey;
1162 }
1163
1164 bool
1165 ItemImpl::isPersistent()
1166 {
1167 return mKeychain;
1168 }
1169
1170 bool
1171 ItemImpl::isModified()
1172 {
1173 StLock<Mutex>_(mMutex);
1174 return mData.get() || mDbAttributes.get();
1175 }
1176
1177 Keychain
1178 ItemImpl::keychain()
1179 {
1180 return mKeychain;
1181 }
1182
1183 bool
1184 ItemImpl::operator < (const ItemImpl &other)
1185 {
1186 if (mData && *mData)
1187 {
1188 // Pointer compare
1189 return this < &other;
1190 }
1191
1192 return mPrimaryKey < other.mPrimaryKey;
1193 }
1194
1195 void
1196 ItemImpl::setAttribute(const CssmDbAttributeInfo &info, const CssmPolyData &data)
1197 {
1198 StLock<Mutex>_(mMutex);
1199 if (!mDbAttributes.get())
1200 {
1201 mDbAttributes.reset(new DbAttributes());
1202 mDbAttributes->recordType(mPrimaryKey->recordType());
1203 }
1204
1205 size_t length = data.Length;
1206 const void *buf = reinterpret_cast<const void *>(data.Data);
1207 uint8 timeString[16];
1208
1209 // XXX This code is duplicated in KCCursorImpl::KCCursorImpl()
1210 // Convert a 4 or 8 byte TIME_DATE to a CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE
1211 // style attribute value.
1212 if (info.format() == CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE)
1213 {
1214 if (length == sizeof(UInt32))
1215 {
1216 MacSecondsToTimeString(*reinterpret_cast<const UInt32 *>(buf), 16, &timeString);
1217 buf = &timeString;
1218 length = 16;
1219 }
1220 else if (length == sizeof(SInt64))
1221 {
1222 MacLongDateTimeToTimeString(*reinterpret_cast<const SInt64 *>(buf), 16, &timeString);
1223 buf = &timeString;
1224 length = 16;
1225 }
1226 }
1227
1228 mDbAttributes->add(info, CssmData(const_cast<void*>(buf), length));
1229 }
1230
1231 void
1232 ItemImpl::modifyContent(const SecKeychainAttributeList *attrList, UInt32 dataLength, const void *inData)
1233 {
1234 StLock<Mutex>_(mMutex);
1235 if (!mDbAttributes.get())
1236 {
1237 mDbAttributes.reset(new DbAttributes());
1238 mDbAttributes->recordType(mPrimaryKey->recordType());
1239 }
1240
1241 if(attrList) // optional
1242 {
1243 for(UInt32 ix=0; ix < attrList->count; ix++)
1244 {
1245 SecKeychainAttrType attrTag = attrList->attr[ix].tag;
1246
1247 if (attrTag == APPLEDB_CSSM_PRINTNAME_ATTRIBUTE)
1248 {
1249 // must remap a caller-supplied kSecKeyPrintName attribute tag for key items, since it isn't in the schema
1250 // (note that this will ultimately match kGenericPrintName in Schema.cpp)
1251 attrTag = kSecLabelItemAttr;
1252 }
1253
1254 mDbAttributes->add(Schema::attributeInfo(attrTag), CssmData(attrList->attr[ix].data, attrList->attr[ix].length));
1255 }
1256 }
1257
1258 if(inData)
1259 {
1260 mData = new CssmDataContainer(inData, dataLength);
1261 }
1262
1263 update();
1264 }
1265
1266 void
1267 ItemImpl::getContent(SecItemClass *itemClass, SecKeychainAttributeList *attrList, UInt32 *length, void **outData)
1268 {
1269 StLock<Mutex>_(mMutex);
1270 // If the data hasn't been set we can't return it.
1271 if (!mKeychain && outData)
1272 {
1273 CssmData *data = mData.get();
1274 if (!data)
1275 MacOSError::throwMe(errSecDataNotAvailable);
1276 }
1277 // TODO: need to check and make sure attrs are valid and handle error condition
1278
1279
1280 if (itemClass)
1281 *itemClass = Schema::itemClassFor(recordType());
1282
1283 bool getDataFromDatabase = mKeychain && mPrimaryKey;
1284 if (getDataFromDatabase) // are we attached to a database?
1285 {
1286 dbUniqueRecord();
1287
1288 // get the number of attributes requested by the caller
1289 UInt32 attrCount = attrList ? attrList->count : 0;
1290
1291 // make a DBAttributes structure and populate it
1292 DbAttributes dbAttributes(mUniqueId->database(), attrCount);
1293 for (UInt32 ix = 0; ix < attrCount; ++ix)
1294 {
1295 dbAttributes.add(Schema::attributeInfo(attrList->attr[ix].tag));
1296 }
1297
1298 // request the data from the database (since we are a reference "item" and the data is really stored there)
1299 CssmDataContainer itemData;
1300 getContent(&dbAttributes, outData ? &itemData : NULL);
1301
1302 // retrieve the data from result
1303 for (UInt32 ix = 0; ix < attrCount; ++ix)
1304 {
1305 if (dbAttributes.at(ix).NumberOfValues > 0)
1306 {
1307 attrList->attr[ix].data = dbAttributes.at(ix).Value[0].Data;
1308 attrList->attr[ix].length = (UInt32)dbAttributes.at(ix).Value[0].Length;
1309
1310 // We don't want the data released, it is up the client
1311 dbAttributes.at(ix).Value[0].Data = NULL;
1312 dbAttributes.at(ix).Value[0].Length = 0;
1313 }
1314 else
1315 {
1316 attrList->attr[ix].data = NULL;
1317 attrList->attr[ix].length = 0;
1318 }
1319 }
1320
1321 // clean up
1322 if (outData)
1323 {
1324 *outData=itemData.data();
1325 itemData.Data = NULL;
1326
1327 if (length)
1328 *length=(UInt32)itemData.length();
1329 itemData.Length = 0;
1330 }
1331 }
1332 else
1333 {
1334 getLocalContent(attrList, length, outData);
1335 }
1336
1337 // Inform anyone interested that we are doing this
1338 #if SENDACCESSNOTIFICATIONS
1339 if (outData)
1340 {
1341 secdebug("kcnotify", "ItemImpl::getContent(%p, %p, %p, %p) retrieved content",
1342 itemClass, attrList, length, outData);
1343
1344 KCEventNotifier::PostKeychainEvent(kSecDataAccessEvent, mKeychain, this);
1345 }
1346 #endif
1347 }
1348
1349 void
1350 ItemImpl::freeContent(SecKeychainAttributeList *attrList, void *data)
1351 {
1352 Allocator &allocator = Allocator::standard(); // @@@ This might not match the one used originally
1353 if (data)
1354 allocator.free(data);
1355
1356 UInt32 attrCount = attrList ? attrList->count : 0;
1357 for (UInt32 ix = 0; ix < attrCount; ++ix)
1358 {
1359 allocator.free(attrList->attr[ix].data);
1360 attrList->attr[ix].data = NULL;
1361 }
1362 }
1363
1364 void
1365 ItemImpl::modifyAttributesAndData(const SecKeychainAttributeList *attrList, UInt32 dataLength, const void *inData)
1366 {
1367 StLock<Mutex>_(mMutex);
1368 if (!mKeychain)
1369 MacOSError::throwMe(errSecNoSuchKeychain);
1370
1371 if (!mDoNotEncrypt)
1372 {
1373 if (!mDbAttributes.get())
1374 {
1375 mDbAttributes.reset(new DbAttributes());
1376 mDbAttributes->recordType(mPrimaryKey->recordType());
1377 }
1378
1379 CSSM_DB_RECORDTYPE recordType = mDbAttributes->recordType();
1380 UInt32 attrCount = attrList ? attrList->count : 0;
1381 for (UInt32 ix = 0; ix < attrCount; ix++)
1382 {
1383 SecKeychainAttrType attrTag = attrList->attr[ix].tag;
1384
1385 if (attrTag == kSecLabelItemAttr)
1386 {
1387 // must remap a caller-supplied label attribute tag for password items, since it isn't in the schema
1388 // (note that this will ultimately match kGenericPrintName in Schema.cpp)
1389 if (IS_PASSWORD_ITEM_CLASS( Schema::itemClassFor(recordType) ))
1390 attrTag = APPLEDB_GENERIC_PRINTNAME_ATTRIBUTE;
1391 }
1392
1393 CssmDbAttributeInfo info=mKeychain->attributeInfoFor(recordType, attrTag);
1394
1395 if (attrList->attr[ix].length || info.AttributeFormat==CSSM_DB_ATTRIBUTE_FORMAT_STRING || info.AttributeFormat==CSSM_DB_ATTRIBUTE_FORMAT_BLOB
1396 || info.AttributeFormat==CSSM_DB_ATTRIBUTE_FORMAT_STRING || info.AttributeFormat==CSSM_DB_ATTRIBUTE_FORMAT_BIG_NUM
1397 || info.AttributeFormat==CSSM_DB_ATTRIBUTE_FORMAT_MULTI_UINT32)
1398 mDbAttributes->add(info, CssmData(attrList->attr[ix].data, attrList->attr[ix].length));
1399 else
1400 mDbAttributes->add(info);
1401 }
1402 }
1403
1404 if(inData)
1405 {
1406 mData = new CssmDataContainer(inData, dataLength);
1407 }
1408
1409 update();
1410 }
1411
1412 void
1413 ItemImpl::getAttributesAndData(SecKeychainAttributeInfo *info, SecItemClass *itemClass,
1414 SecKeychainAttributeList **attrList, UInt32 *length, void **outData)
1415 {
1416 StLock<Mutex>_(mMutex);
1417 // If the data hasn't been set we can't return it.
1418 if (!mKeychain && outData)
1419 {
1420 CssmData *data = mData.get();
1421 if (!data)
1422 MacOSError::throwMe(errSecDataNotAvailable);
1423 }
1424 // TODO: need to check and make sure attrs are valid and handle error condition
1425
1426 SecItemClass myItemClass = Schema::itemClassFor(recordType());
1427 if (itemClass)
1428 *itemClass = myItemClass;
1429
1430 // @@@ This call won't work for floating items (like certificates).
1431 dbUniqueRecord();
1432
1433 UInt32 attrCount = info ? info->count : 0;
1434 DbAttributes dbAttributes(mUniqueId->database(), attrCount);
1435 for (UInt32 ix = 0; ix < attrCount; ix++)
1436 {
1437 CssmDbAttributeData &record = dbAttributes.add();
1438 record.Info.AttributeNameFormat=CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER;
1439 record.Info.Label.AttributeID=info->tag[ix];
1440
1441 if (record.Info.Label.AttributeID == kSecLabelItemAttr)
1442 {
1443 // must remap a caller-supplied label attribute tag for password items, since it isn't in the schema
1444 if (IS_PASSWORD_ITEM_CLASS( myItemClass ))
1445 record.Info.Label.AttributeID = APPLEDB_GENERIC_PRINTNAME_ATTRIBUTE;
1446 }
1447 }
1448
1449 CssmDataContainer itemData;
1450 getContent(&dbAttributes, outData ? &itemData : NULL);
1451
1452 if (info && attrList)
1453 {
1454 SecKeychainAttributeList *theList=reinterpret_cast<SecKeychainAttributeList *>(malloc(sizeof(SecKeychainAttributeList)));
1455 SecKeychainAttribute *attr=reinterpret_cast<SecKeychainAttribute *>(malloc(sizeof(SecKeychainAttribute)*attrCount));
1456 theList->count=attrCount;
1457 theList->attr=attr;
1458
1459 for (UInt32 ix = 0; ix < attrCount; ++ix)
1460 {
1461 attr[ix].tag=info->tag[ix];
1462
1463 if (dbAttributes.at(ix).NumberOfValues > 0)
1464 {
1465 attr[ix].data = dbAttributes.at(ix).Value[0].Data;
1466 attr[ix].length = (UInt32)dbAttributes.at(ix).Value[0].Length;
1467
1468 // We don't want the data released, it is up the client
1469 dbAttributes.at(ix).Value[0].Data = NULL;
1470 dbAttributes.at(ix).Value[0].Length = 0;
1471 }
1472 else
1473 {
1474 attr[ix].data = NULL;
1475 attr[ix].length = 0;
1476 }
1477 }
1478 *attrList=theList;
1479 }
1480
1481 if (outData)
1482 {
1483 *outData=itemData.data();
1484 itemData.Data=NULL;
1485
1486 if (length) *length=(UInt32)itemData.length();
1487 itemData.Length=0;
1488
1489 #if SENDACCESSNOTIFICATIONS
1490 secdebug("kcnotify", "ItemImpl::getAttributesAndData(%p, %p, %p, %p, %p) retrieved data",
1491 info, itemClass, attrList, length, outData);
1492
1493 KCEventNotifier::PostKeychainEvent(kSecDataAccessEvent, mKeychain, this);
1494 #endif
1495 }
1496
1497 }
1498
1499 void
1500 ItemImpl::freeAttributesAndData(SecKeychainAttributeList *attrList, void *data)
1501 {
1502 Allocator &allocator = Allocator::standard(); // @@@ This might not match the one used originally
1503
1504 if (data)
1505 allocator.free(data);
1506
1507 if (attrList)
1508 {
1509 for (UInt32 ix = 0; ix < attrList->count; ++ix)
1510 {
1511 allocator.free(attrList->attr[ix].data);
1512 }
1513 free(attrList->attr);
1514 free(attrList);
1515 }
1516 }
1517
1518 void
1519 ItemImpl::getAttribute(SecKeychainAttribute& attr, UInt32 *actualLength)
1520 {
1521 StLock<Mutex>_(mMutex);
1522 if (attr.tag == kSecClassItemAttr)
1523 return getClass(attr, actualLength);
1524
1525 if (mDbAttributes.get())
1526 {
1527 CssmDbAttributeData *data = mDbAttributes->find(Schema::attributeInfo(attr.tag));
1528 if (data)
1529 {
1530 getAttributeFrom(data, attr, actualLength);
1531 return;
1532 }
1533 }
1534
1535 if (!mKeychain)
1536 MacOSError::throwMe(errSecNoSuchAttr);
1537
1538 dbUniqueRecord();
1539 DbAttributes dbAttributes(mUniqueId->database(), 1);
1540 dbAttributes.add(Schema::attributeInfo(attr.tag));
1541 mUniqueId->get(&dbAttributes, NULL);
1542 getAttributeFrom(&dbAttributes.at(0), attr, actualLength);
1543 }
1544
1545 void
1546 ItemImpl::getAttributeFrom(CssmDbAttributeData *data, SecKeychainAttribute &attr, UInt32 *actualLength)
1547 {
1548 StLock<Mutex>_(mMutex);
1549 static const uint32 zero = 0;
1550 UInt32 length;
1551 const void *buf = NULL;
1552
1553 // Temporary storage for buf.
1554 sint64 macLDT;
1555 uint32 macSeconds;
1556 sint16 svalue16;
1557 uint16 uvalue16;
1558 sint8 svalue8;
1559 uint8 uvalue8;
1560
1561 if (!data)
1562 length = 0;
1563 else if (data->size() < 1) // Attribute has no values.
1564 {
1565 if (data->format() == CSSM_DB_ATTRIBUTE_FORMAT_SINT32
1566 || data->format() == CSSM_DB_ATTRIBUTE_FORMAT_UINT32)
1567 {
1568 length = sizeof(zero);
1569 buf = &zero;
1570 }
1571 else if (CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE)
1572 length = 0; // Should we throw here?
1573 else // All other formats
1574 length = 0;
1575 }
1576 else // Get the first value
1577 {
1578 length = (UInt32)data->Value[0].Length;
1579 buf = data->Value[0].Data;
1580
1581 if (data->format() == CSSM_DB_ATTRIBUTE_FORMAT_SINT32)
1582 {
1583 if (attr.length == sizeof(sint8))
1584 {
1585 length = attr.length;
1586 svalue8 = sint8(*reinterpret_cast<const sint32 *>(buf));
1587 buf = &svalue8;
1588 }
1589 else if (attr.length == sizeof(sint16))
1590 {
1591 length = attr.length;
1592 svalue16 = sint16(*reinterpret_cast<const sint32 *>(buf));
1593 buf = &svalue16;
1594 }
1595 }
1596 else if (data->format() == CSSM_DB_ATTRIBUTE_FORMAT_UINT32)
1597 {
1598 if (attr.length == sizeof(uint8))
1599 {
1600 length = attr.length;
1601 uvalue8 = uint8(*reinterpret_cast<const uint32 *>(buf));
1602 buf = &uvalue8;
1603 }
1604 else if (attr.length == sizeof(uint16))
1605 {
1606 length = attr.length;
1607 uvalue16 = uint16(*reinterpret_cast<const uint32 *>(buf));
1608 buf = &uvalue16;
1609 }
1610 }
1611 else if (data->format() == CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE)
1612 {
1613 if (attr.length == sizeof(uint32))
1614 {
1615 TimeStringToMacSeconds(data->Value[0], macSeconds);
1616 buf = &macSeconds;
1617 length = attr.length;
1618 }
1619 else if (attr.length == sizeof(sint64))
1620 {
1621 TimeStringToMacLongDateTime(data->Value[0], macLDT);
1622 buf = &macLDT;
1623 length = attr.length;
1624 }
1625 }
1626 }
1627
1628 if (actualLength)
1629 *actualLength = length;
1630
1631 if (length)
1632 {
1633 if (attr.length < length)
1634 MacOSError::throwMe(errSecBufferTooSmall);
1635
1636 memcpy(attr.data, buf, length);
1637 }
1638 }
1639
1640 void
1641 ItemImpl::getData(CssmDataContainer& outData)
1642 {
1643 StLock<Mutex>_(mMutex);
1644 if (!mKeychain)
1645 {
1646 CssmData *data = mData.get();
1647 // If the data hasn't been set we can't return it.
1648 if (!data)
1649 MacOSError::throwMe(errSecDataNotAvailable);
1650
1651 outData = *data;
1652 return;
1653 }
1654
1655 getContent(NULL, &outData);
1656
1657 #if SENDACCESSNOTIFICATIONS
1658 secdebug("kcnotify", "ItemImpl::getData retrieved data");
1659
1660 //%%%<might> be done elsewhere, but here is good for now
1661 KCEventNotifier::PostKeychainEvent(kSecDataAccessEvent, mKeychain, this);
1662 #endif
1663 }
1664
1665 SSGroup
1666 ItemImpl::group()
1667 {
1668 StLock<Mutex>_(mMutex);
1669 SSGroup group;
1670 if (!!mUniqueId)
1671 {
1672 Db db(mKeychain->database());
1673 if (useSecureStorage(db))
1674 {
1675 group = safer_cast<SSDbUniqueRecordImpl &>(*mUniqueId).group();
1676 }
1677 }
1678
1679 return group;
1680 }
1681
1682 void ItemImpl::getLocalContent(SecKeychainAttributeList *attributeList, UInt32 *outLength, void **outData)
1683 {
1684 StLock<Mutex>_(mMutex);
1685 willRead();
1686 Allocator &allocator = Allocator::standard(); // @@@ This might not match the one used originally
1687 if (outData)
1688 {
1689 CssmData *data = mData.get();
1690 if (!data)
1691 MacOSError::throwMe(errSecDataNotAvailable);
1692
1693 // Copy the data out of our internal cached copy.
1694 UInt32 length = (UInt32)data->Length;
1695 *outData = allocator.malloc(length);
1696 memcpy(*outData, data->Data, length);
1697 if (outLength)
1698 *outLength = length;
1699 }
1700
1701 if (attributeList)
1702 {
1703 if (!mDbAttributes.get())
1704 MacOSError::throwMe(errSecDataNotAvailable);
1705
1706 // Pull attributes out of a "floating" item, i.e. one that isn't attached to a database
1707 for (UInt32 ix = 0; ix < attributeList->count; ++ix)
1708 {
1709 SecKeychainAttribute &attribute = attributeList->attr[ix];
1710 CssmDbAttributeData *data = mDbAttributes->find(Schema::attributeInfo(attribute.tag));
1711 if (data && data->NumberOfValues > 0)
1712 {
1713 // Copy the data out of our internal cached copy.
1714 UInt32 length = (UInt32)data->Value[0].Length;
1715 attribute.data = allocator.malloc(length);
1716 memcpy(attribute.data, data->Value[0].Data, length);
1717 attribute.length = length;
1718 }
1719 else
1720 {
1721 attribute.length = 0;
1722 attribute.data = NULL;
1723 }
1724 }
1725 }
1726 }
1727
1728 void
1729 ItemImpl::getContent(DbAttributes *dbAttributes, CssmDataContainer *itemData)
1730 {
1731 StLock<Mutex>_(mMutex);
1732 // Make sure mUniqueId is set.
1733 dbUniqueRecord();
1734 if (itemData)
1735 {
1736 Db db(mUniqueId->database());
1737 if (mDoNotEncrypt)
1738 {
1739 mUniqueId->getWithoutEncryption (dbAttributes, itemData);
1740 return;
1741 }
1742 if (useSecureStorage(db))
1743 {
1744 SSDbUniqueRecordImpl* impl = dynamic_cast<SSDbUniqueRecordImpl *>(&(*mUniqueId));
1745 if (impl == NULL)
1746 {
1747 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER);
1748 }
1749
1750 SSDbUniqueRecord ssUniqueId(impl);
1751 const AccessCredentials *autoPrompt = globals().itemCredentials();
1752 ssUniqueId->get(dbAttributes, itemData, autoPrompt);
1753 return;
1754 }
1755 }
1756
1757 mUniqueId->get(dbAttributes, itemData);
1758 }
1759
1760 bool
1761 ItemImpl::useSecureStorage(const Db &db)
1762 {
1763 StLock<Mutex>_(mMutex);
1764 switch (recordType())
1765 {
1766 case CSSM_DL_DB_RECORD_GENERIC_PASSWORD:
1767 case CSSM_DL_DB_RECORD_INTERNET_PASSWORD:
1768 case CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD:
1769 if (db->dl()->subserviceMask() & CSSM_SERVICE_CSP)
1770 return true;
1771 break;
1772 default:
1773 break;
1774 }
1775 return false;
1776 }
1777
1778 void ItemImpl::willRead()
1779 {
1780 }
1781
1782 Item ItemImpl::makeFromPersistentReference(const CFDataRef persistentRef, bool *isIdentityRef)
1783 {
1784 CssmData dictData((void*)::CFDataGetBytePtr(persistentRef), ::CFDataGetLength(persistentRef));
1785 NameValueDictionary dict(dictData);
1786
1787 Keychain keychain;
1788 Item item = (ItemImpl *) NULL;
1789
1790 if (isIdentityRef) {
1791 *isIdentityRef = (dict.FindByName(IDENTITY_KEY) != 0) ? true : false;
1792 }
1793
1794 // make sure we have a database identifier
1795 if (dict.FindByName(SSUID_KEY) != 0)
1796 {
1797 DLDbIdentifier dlDbIdentifier = NameValueDictionary::MakeDLDbIdentifierFromNameValueDictionary(dict);
1798 DLDbIdentifier newDlDbIdentifier(dlDbIdentifier.ssuid(),
1799 DLDbListCFPref::ExpandTildesInPath(dlDbIdentifier.dbName()).c_str(),
1800 dlDbIdentifier.dbLocation());
1801
1802 keychain = globals().storageManager.keychain(newDlDbIdentifier);
1803
1804 const NameValuePair* aDictItem = dict.FindByName(ITEM_KEY);
1805 if (aDictItem && keychain)
1806 {
1807 PrimaryKey primaryKey(aDictItem->Value());
1808 item = keychain->item(primaryKey);
1809 }
1810 }
1811 KCThrowIf_( !item, errSecItemNotFound );
1812 return item;
1813 }
1814
1815 void ItemImpl::copyPersistentReference(CFDataRef &outDataRef, bool isSecIdentityRef)
1816 {
1817 if (secd_PersistentRef) {
1818 outDataRef = secd_PersistentRef;
1819 return;
1820 }
1821 StLock<Mutex>_(mMutex);
1822 // item must be in a keychain and have a primary key to be persistent
1823 if (!mKeychain || !mPrimaryKey) {
1824 MacOSError::throwMe(errSecItemNotFound);
1825 }
1826 DLDbIdentifier dlDbIdentifier = mKeychain->dlDbIdentifier();
1827 DLDbIdentifier newDlDbIdentifier(dlDbIdentifier.ssuid(),
1828 DLDbListCFPref::AbbreviatedPath(mKeychain->name()).c_str(),
1829 dlDbIdentifier.dbLocation());
1830 NameValueDictionary dict;
1831 NameValueDictionary::MakeNameValueDictionaryFromDLDbIdentifier(newDlDbIdentifier, dict);
1832
1833 CssmData* pKey = mPrimaryKey;
1834 dict.Insert (new NameValuePair(ITEM_KEY, *pKey));
1835
1836 if (isSecIdentityRef) {
1837 uint32_t value = -1;
1838 CssmData valueData((void*)&value, sizeof(value));
1839 dict.Insert (new NameValuePair(IDENTITY_KEY, valueData));
1840 }
1841
1842 // flatten the NameValueDictionary
1843 CssmData dictData;
1844 dict.Export(dictData);
1845 outDataRef = ::CFDataCreate(kCFAllocatorDefault, dictData.Data, dictData.Length);
1846 free (dictData.Data);
1847 }
1848
1849 void ItemImpl::copyRecordIdentifier(CSSM_DATA &data)
1850 {
1851 StLock<Mutex>_(mMutex);
1852 CssmClient::DbUniqueRecord uniqueRecord = dbUniqueRecord ();
1853 uniqueRecord->getRecordIdentifier(data);
1854 }
1855
1856 /*
1857 * Obtain blob used to bind a keychain item to an Extended Attribute record.
1858 * We just use the PrimaryKey blob as the default. Note that for standard Items,
1859 * this can cause the loss of extended attribute bindings if a Primary Key
1860 * attribute changes.
1861 */
1862 const CssmData &ItemImpl::itemID()
1863 {
1864 StLock<Mutex>_(mMutex);
1865 if(mPrimaryKey->length() == 0) {
1866 /* not in a keychain; we don't have a primary key */
1867 MacOSError::throwMe(errSecNoSuchAttr);
1868 }
1869 return *mPrimaryKey;
1870 }
1871
1872 bool ItemImpl::equal(SecCFObject &other)
1873 {
1874 // First check to see if both items have a primary key and
1875 // if the primary key is the same. If so then these
1876 // items must be equal
1877 ItemImpl& other_item = (ItemImpl&)other;
1878 if (mPrimaryKey != NULL && mPrimaryKey == other_item.mPrimaryKey)
1879 {
1880 return true;
1881 }
1882
1883 // The primary keys do not match so do a CFHash of the
1884 // data of the item and compare those for equality
1885 CFHashCode this_hash = hash();
1886 CFHashCode other_hash = other.hash();
1887 return (this_hash == other_hash);
1888 }
1889
1890 CFHashCode ItemImpl::hash()
1891 {
1892 CFHashCode result = SecCFObject::hash();
1893
1894 StLock<Mutex>_(mMutex);
1895 RefPointer<CssmDataContainer> data_to_hash;
1896
1897 // Use the item data for the hash
1898 if (mData && *mData)
1899 {
1900 data_to_hash = mData;
1901 }
1902
1903 // If there is no primary key AND not data ????
1904 // just return the 'old' hash value which is the
1905 // object pointer.
1906 if (NULL != data_to_hash.get())
1907 {
1908 CFDataRef temp_data = NULL;
1909 unsigned char digest[CC_SHA256_DIGEST_LENGTH];
1910
1911 if (data_to_hash->length() < 80)
1912 {
1913 // If it is less than 80 bytes then CFData can be used
1914 temp_data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
1915 (const UInt8 *)data_to_hash->data(), data_to_hash->length(), kCFAllocatorNull);
1916
1917 }
1918 // CFData truncates its hash value to 80 bytes. ????
1919 // In order to do the 'right thing' a SHA 256 hash will be used to
1920 // include all of the data
1921 else
1922 {
1923 memset(digest, 0, CC_SHA256_DIGEST_LENGTH);
1924
1925 CC_SHA256((const void *)data_to_hash->data(), (CC_LONG)data_to_hash->length(), digest);
1926
1927 temp_data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
1928 (const UInt8 *)digest, CC_SHA256_DIGEST_LENGTH, kCFAllocatorNull);
1929 }
1930
1931 if (NULL != temp_data)
1932 {
1933 result = CFHash(temp_data);
1934 CFRelease(temp_data);
1935 }
1936
1937 }
1938
1939 return result;
1940 }
1941
1942
1943 void ItemImpl::postItemEvent(SecKeychainEvent theEvent)
1944 {
1945 mKeychain->postEvent(theEvent, this);
1946 }
1947
1948
1949
1950 //
1951 // Item -- This class is here to magically create the right subclass of ItemImpl
1952 // when constructing new items.
1953 //
1954 Item::Item()
1955 {
1956 }
1957
1958 Item::Item(ItemImpl *impl) : SecPointer<ItemImpl>(impl)
1959 {
1960 }
1961
1962 Item::Item(SecItemClass itemClass, OSType itemCreator, UInt32 length, const void* data, bool inhibitCheck)
1963 {
1964 if (!inhibitCheck)
1965 {
1966 if (itemClass == CSSM_DL_DB_RECORD_X509_CERTIFICATE
1967 || itemClass == CSSM_DL_DB_RECORD_PUBLIC_KEY
1968 || itemClass == CSSM_DL_DB_RECORD_PRIVATE_KEY
1969 || itemClass == CSSM_DL_DB_RECORD_SYMMETRIC_KEY)
1970 MacOSError::throwMe(errSecNoSuchClass); /* @@@ errSecInvalidClass */
1971 }
1972
1973 *this = new ItemImpl(itemClass, itemCreator, length, data, inhibitCheck);
1974 }
1975
1976 Item::Item(SecItemClass itemClass, SecKeychainAttributeList *attrList, UInt32 length, const void* data)
1977 {
1978 *this = new ItemImpl(itemClass, attrList, length, data);
1979 }
1980
1981 Item::Item(const Keychain &keychain, const PrimaryKey &primaryKey, const CssmClient::DbUniqueRecord &uniqueId)
1982 : SecPointer<ItemImpl>(
1983 primaryKey->recordType() == CSSM_DL_DB_RECORD_X509_CERTIFICATE
1984 ? Certificate::make(keychain, primaryKey, uniqueId)
1985 : (primaryKey->recordType() == CSSM_DL_DB_RECORD_PUBLIC_KEY
1986 || primaryKey->recordType() == CSSM_DL_DB_RECORD_PRIVATE_KEY
1987 || primaryKey->recordType() == CSSM_DL_DB_RECORD_SYMMETRIC_KEY)
1988 ? KeyItem::make(keychain, primaryKey, uniqueId)
1989 : primaryKey->recordType() == CSSM_DL_DB_RECORD_EXTENDED_ATTRIBUTE
1990 ? ExtendedAttribute::make(keychain, primaryKey, uniqueId)
1991 : ItemImpl::make(keychain, primaryKey, uniqueId))
1992 {
1993 }
1994
1995 Item::Item(const Keychain &keychain, const PrimaryKey &primaryKey)
1996 : SecPointer<ItemImpl>(
1997 primaryKey->recordType() == CSSM_DL_DB_RECORD_X509_CERTIFICATE
1998 ? Certificate::make(keychain, primaryKey)
1999 : (primaryKey->recordType() == CSSM_DL_DB_RECORD_PUBLIC_KEY
2000 || primaryKey->recordType() == CSSM_DL_DB_RECORD_PRIVATE_KEY
2001 || primaryKey->recordType() == CSSM_DL_DB_RECORD_SYMMETRIC_KEY)
2002 ? KeyItem::make(keychain, primaryKey)
2003 : primaryKey->recordType() == CSSM_DL_DB_RECORD_EXTENDED_ATTRIBUTE
2004 ? ExtendedAttribute::make(keychain, primaryKey)
2005 : ItemImpl::make(keychain, primaryKey))
2006 {
2007 }
2008
2009 Item::Item(ItemImpl &item)
2010 : SecPointer<ItemImpl>(
2011 item.recordType() == CSSM_DL_DB_RECORD_X509_CERTIFICATE
2012 ? new Certificate(safer_cast<Certificate &>(item))
2013 : (item.recordType() == CSSM_DL_DB_RECORD_PUBLIC_KEY
2014 || item.recordType() == CSSM_DL_DB_RECORD_PRIVATE_KEY
2015 || item.recordType() == CSSM_DL_DB_RECORD_SYMMETRIC_KEY)
2016 ? new KeyItem(safer_cast<KeyItem &>(item))
2017 : item.recordType() == CSSM_DL_DB_RECORD_EXTENDED_ATTRIBUTE
2018 ? new ExtendedAttribute(safer_cast<ExtendedAttribute &>(item))
2019 : new ItemImpl(item))
2020 {
2021 }
2022
2023 CFIndex KeychainCore::GetItemRetainCount(Item& item)
2024 {
2025 return CFGetRetainCount(item->handle(false));
2026 }
2027
2028 void ItemImpl::setPersistentRef(CFDataRef ref)
2029 {
2030 if (secd_PersistentRef) {
2031 CFRelease(secd_PersistentRef);
2032 }
2033 secd_PersistentRef = ref;
2034 CFRetain(ref);
2035 }
2036
2037 CFDataRef ItemImpl::getPersistentRef()
2038 {
2039 return secd_PersistentRef;
2040 }
2041
2042
2043
2044 bool ItemImpl::mayDelete()
2045 {
2046 ObjectImpl* uniqueIDImpl = mUniqueId.get();
2047
2048 if (uniqueIDImpl != NULL)
2049 {
2050 bool result = mUniqueId->isIdle();
2051 return result;
2052 }
2053 else
2054 {
2055 return true;
2056 }
2057 }