2  * Copyright (c) 2000-2004,2011-2014 Apple Inc. All Rights Reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   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 
  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. 
  21  * @APPLE_LICENSE_HEADER_END@ 
  31 #include "Certificate.h" 
  33 #include "ExtendedAttribute.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> 
  48 #include <security_utilities/CSPDLTransaction.h> 
  49 #include <Security/SecBasePriv.h> 
  51 //%%% schema indexes should be defined in Schema.h 
  52 #define _kSecAppleSharePasswordItemClass                'ashp' 
  53 #define APPLEDB_CSSM_PRINTNAME_ATTRIBUTE        1   /* schema index for label attribute of keys or certificates */ 
  54 #define APPLEDB_GENERIC_PRINTNAME_ATTRIBUTE     7   /* schema index for label attribute of password items */ 
  55 #define IS_PASSWORD_ITEM_CLASS(X)             ( (X) == kSecInternetPasswordItemClass || \ 
  56                                                 (X) == kSecGenericPasswordItemClass || \ 
  57                                                 (X) == _kSecAppleSharePasswordItemClass ) ? 1 : 0 
  59 using namespace KeychainCore
; 
  60 using namespace CSSMDateTimeUtils
; 
  66 ItemImpl 
*ItemImpl::required(SecKeychainItemRef ptr
) 
  69         if (ItemImpl 
*pp 
= optional(ptr
)) { 
  73     MacOSError::throwMe(errSecInvalidItemRef
); 
  76 ItemImpl 
*ItemImpl::optional(SecKeychainItemRef ptr
) 
  78     if (ptr 
!= NULL 
&& CFGetTypeID(ptr
) == SecKeyGetTypeID()) { 
  79         return dynamic_cast<ItemImpl 
*>(KeyItem::fromSecKeyRef(ptr
)); 
  80     } else if (SecCFObject 
*p 
= SecCFObject::optional(ptr
)) { 
  81         if (ItemImpl 
*pp 
= dynamic_cast<ItemImpl 
*>(p
)) { 
  84             MacOSError::throwMe(errSecInvalidItemRef
); 
  91 // NewItemImpl constructor 
  92 ItemImpl::ItemImpl(SecItemClass itemClass
, OSType itemCreator
, UInt32 length
, const void* data
, bool dontDoAttributes
) 
  93         : mDbAttributes(new DbAttributes()), 
  95         secd_PersistentRef(NULL
), 
  98         mMutex(Mutex::recursive
) 
 101                 mData 
= new CssmDataContainer(data
, length
); 
 103         mDbAttributes
->recordType(Schema::recordTypeFor(itemClass
)); 
 106                 mDbAttributes
->add(Schema::attributeInfo(kSecCreatorItemAttr
), itemCreator
); 
 109 ItemImpl::ItemImpl(SecItemClass itemClass
, SecKeychainAttributeList 
*attrList
, UInt32 length
, const void* data
) 
 110         : mDbAttributes(new DbAttributes()), 
 112         secd_PersistentRef(NULL
), 
 113         mDoNotEncrypt(false), 
 115         mMutex(Mutex::recursive
) 
 118                 mData 
= new CssmDataContainer(data
, length
); 
 121         mDbAttributes
->recordType(Schema::recordTypeFor(itemClass
)); 
 125                 for(UInt32 i
=0; i 
< attrList
->count
; i
++) 
 127                         mDbAttributes
->add(Schema::attributeInfo(attrList
->attr
[i
].tag
), CssmData(attrList
->attr
[i
].data
,  attrList
->attr
[i
].length
)); 
 132 // DbItemImpl constructor 
 133 ItemImpl::ItemImpl(const Keychain 
&keychain
, const PrimaryKey 
&primaryKey
, const DbUniqueRecord 
&uniqueId
) 
 134         : mUniqueId(uniqueId
), mKeychain(keychain
), mPrimaryKey(primaryKey
), 
 135         secd_PersistentRef(NULL
), mDoNotEncrypt(false), mInCache(false), 
 136         mMutex(Mutex::recursive
) 
 140 // PrimaryKey ItemImpl constructor 
 141 ItemImpl::ItemImpl(const Keychain 
&keychain
, const PrimaryKey 
&primaryKey
) 
 142 : mKeychain(keychain
), mPrimaryKey(primaryKey
), secd_PersistentRef(NULL
), mDoNotEncrypt(false), 
 144         mMutex(Mutex::recursive
) 
 148 ItemImpl
* ItemImpl::make(const Keychain 
&keychain
, const PrimaryKey 
&primaryKey
, const CssmClient::DbUniqueRecord 
&uniqueId
) 
 150         ItemImpl
* ii 
= new ItemImpl(keychain
, primaryKey
, uniqueId
); 
 151         keychain
->addItem(primaryKey
, ii
); 
 157 ItemImpl
* ItemImpl::make(const Keychain 
&keychain
, const PrimaryKey 
&primaryKey
) 
 159         ItemImpl
* ii 
= new ItemImpl(keychain
, primaryKey
); 
 160         keychain
->addItem(primaryKey
, ii
); 
 166 // Constructor used when copying an item to a keychain. 
 168 ItemImpl::ItemImpl(ItemImpl 
&item
) : 
 169         mData(item
.modifiedData() ? NULL 
: new CssmDataContainer()), 
 170         mDbAttributes(new DbAttributes()), 
 172         secd_PersistentRef(NULL
), 
 173         mDoNotEncrypt(false), 
 175         mMutex(Mutex::recursive
) 
 177         mDbAttributes
->recordType(item
.recordType()); 
 179         if (item
.mKeychain
) { 
 180                 // get the entire source item from its keychain. This requires figuring 
 181                 // out the schema for the item based on its record type. 
 182         // Ask the remote item to fill our attributes dictionary, because it probably has an attached keychain to ask 
 183         item
.fillDbAttributesFromSchema(*mDbAttributes
, item
.recordType()); 
 185         item
.getContent(mDbAttributes
.get(), mData
.get()); 
 188     // @@@ We don't deal with modified attributes. 
 190         if (item
.modifiedData()) 
 191                 // the copied data comes from the source item 
 192                 mData 
= new CssmDataContainer(item
.modifiedData()->Data
, 
 193                         item
.modifiedData()->Length
); 
 196 ItemImpl::~ItemImpl() 
 198         if (secd_PersistentRef
) { 
 199                 CFRelease(secd_PersistentRef
); 
 203     /* if we get an exception in destructor, presumably the mutex, lets throw if we 
 204      * are in a debug build (ie reach end of block) */ 
 214 ItemImpl::getMutexForObject() const 
 218                 return mKeychain
->getKeychainMutex(); 
 226 ItemImpl::aboutToDestruct() 
 228     if(mKeychain
.get()) { 
 229         mKeychain
->forceRemoveFromCache(this); 
 236 ItemImpl::didModify() 
 238         StLock
<Mutex
>_(mMutex
); 
 240         mDbAttributes
.reset(NULL
); 
 244 ItemImpl::defaultAttributeValue(const CSSM_DB_ATTRIBUTE_INFO 
&info
) 
 246         static const uint32 zeroInt 
= 0; 
 247         static const double zeroDouble 
= 0.0; 
 248         static const char timeBytes
[] = "20010101000000Z"; 
 250         static const CSSM_DATA defaultFourBytes 
= { 4, (uint8 
*) &zeroInt 
}; 
 251         static const CSSM_DATA defaultEightBytes 
= { 8, (uint8 
*) &zeroDouble 
}; 
 252         static const CSSM_DATA defaultTime 
= { 16, (uint8 
*) timeBytes 
}; 
 253         static const CSSM_DATA defaultZeroBytes 
= { 0, NULL 
}; 
 255         switch (info
.AttributeFormat
) 
 257                 case CSSM_DB_ATTRIBUTE_FORMAT_SINT32
: 
 258                 case CSSM_DB_ATTRIBUTE_FORMAT_UINT32
: 
 259                         return defaultFourBytes
; 
 261                 case CSSM_DB_ATTRIBUTE_FORMAT_REAL
: 
 262                         return defaultEightBytes
; 
 264                 case CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE
: 
 268                         return defaultZeroBytes
; 
 272 void ItemImpl::fillDbAttributesFromSchema(DbAttributes
& dbAttributes
, CSSM_DB_RECORDTYPE recordType
, Keychain keychain
) { 
 273     // If we weren't passed a keychain, use our own. 
 274     keychain 
= !!keychain 
? keychain 
: mKeychain
; 
 276     // Without a keychain, there's no one to ask. 
 281     SecKeychainAttributeInfo
* infos
; 
 282     keychain
->getAttributeInfoForItemID(recordType
, &infos
); 
 284     secinfo("integrity", "filling %u attributes for type %u", (unsigned int)infos
->count
, recordType
); 
 286     for (uint32 i 
= 0; i 
< infos
->count
; i
++) { 
 287         CSSM_DB_ATTRIBUTE_INFO info
; 
 288         memset(&info
, 0, sizeof(info
)); 
 290         info
.AttributeNameFormat 
= CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER
; 
 291         info
.Label
.AttributeID 
= infos
->tag
[i
]; 
 292         info
.AttributeFormat 
= infos
->format
[i
]; 
 294         dbAttributes
.add(info
); 
 297     keychain
->freeAttributeInfo(infos
); 
 300 DbAttributes
* ItemImpl::getCurrentAttributes() { 
 301     DbAttributes
* dbAttributes
; 
 302     secinfo("integrity", "getting current attributes..."); 
 304     if(mUniqueId
.get()) { 
 305         // If we have a unique id, there's an item in the database backing us. Ask for its attributes. 
 306         dbAttributes 
= new DbAttributes(dbUniqueRecord()->database(), 1); 
 307         fillDbAttributesFromSchema(*dbAttributes
, recordType()); 
 308         mUniqueId
->get(dbAttributes
, NULL
); 
 310         // and fold in any updates. 
 311         if(mDbAttributes
.get()) { 
 312             secinfo("integrity", "adding %d attributes from mDbAttributes", mDbAttributes
->size()); 
 313             dbAttributes
->updateWithDbAttributes(&(*mDbAttributes
.get())); 
 315     } else if (mDbAttributes
.get()) { 
 316         // We don't have a backing item, so all our attributes are in mDbAttributes. Copy them. 
 317         secnotice("integrity", "no unique id, using %d attributes from mDbAttributes", mDbAttributes
->size()); 
 318         dbAttributes 
= new DbAttributes(); 
 319         dbAttributes
->updateWithDbAttributes(&(*mDbAttributes
.get())); 
 321         // No attributes at all. We should maybe throw here, but let's not. 
 322         secnotice("integrity", "no attributes at all"); 
 323         dbAttributes 
= new DbAttributes(); 
 325     dbAttributes
->recordType(recordType()); 
 326     // TODO: We don't set semanticInformation. Issue? 
 332 void ItemImpl::encodeAttributes(CssmOwnedData 
&attributeBlob
) { 
 333     // Sometimes we don't have our attributes. Find them. 
 334     auto_ptr
<DbAttributes
> dbAttributes(getCurrentAttributes()); 
 335     encodeAttributesFromDictionary(attributeBlob
, dbAttributes
.get()); 
 339 void ItemImpl::encodeAttributesFromDictionary(CssmOwnedData 
&attributeBlob
, DbAttributes
* dbAttributes
) { 
 340     // Create a CFDictionary from dbAttributes and call der_encode_dictionary on it 
 341     CFRef
<CFMutableDictionaryRef
> attributes
; 
 342     attributes
.take(CFDictionaryCreateMutable(NULL
, dbAttributes
->size(), &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
)); 
 344     secinfo("integrity", "looking at %d attributes", dbAttributes
->size()); 
 345     // TODO: include record type and semantic information? 
 347     for(int i 
= 0; i 
< dbAttributes
->size(); i
++) { 
 348         CssmDbAttributeData
& data 
= dbAttributes
->attributes()[i
]; 
 349         CssmDbAttributeInfo
& datainfo 
= data
.info(); 
 351         // Sometimes we need to normalize the info. Calling Schema::attributeInfo is the best way to do that. 
 352         // There's no avoiding the try-catch structure here, since only some of the names are in Schema::attributeInfo, 
 353         // but it will only indicate that by throwing. 
 354         CssmDbAttributeInfo
& actualInfo 
= datainfo
; 
 356             if(datainfo
.nameFormat() == CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER 
&& Schema::haveAttributeInfo(datainfo
.intName())) { 
 357                 actualInfo 
= Schema::attributeInfo(datainfo
.intName()); 
 360             actualInfo 
= datainfo
; 
 363         // Pull the label/name out of this data 
 364         CFRef
<CFDataRef
> label 
= NULL
; 
 366         switch(actualInfo
.nameFormat()) { 
 367             case CSSM_DB_ATTRIBUTE_NAME_AS_STRING
: { 
 368                 const char* stringname 
= actualInfo
.stringName(); 
 369                 label
.take(CFDataCreate(NULL
, reinterpret_cast<const UInt8
*>(stringname
), strlen(stringname
))); 
 372             case CSSM_DB_ATTRIBUTE_NAME_AS_OID
: { 
 373                 const CssmOid
& oidname 
= actualInfo
.oidName(); 
 374                 label
.take(CFDataCreate(NULL
, reinterpret_cast<const UInt8
*>(oidname
.data()), oidname
.length())); 
 377             case CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER
: { 
 378                 uint32 iname 
= actualInfo
.intName(); 
 379                 label
.take(CFDataCreate(NULL
, reinterpret_cast<const UInt8
*>(&(iname
)), sizeof(uint32
))); 
 384         if(data
.size() == 0) { 
 385             // This attribute doesn't have a value, and so shouldn't be included in the digest. 
 389         // Do not include the Creation or Modification date attributes in the hash. 
 390         // Use this complicated method of checking so we'll catch string and integer names. 
 391         SecKeychainAttrType cdat 
= kSecCreationDateItemAttr
; 
 392         SecKeychainAttrType cmod 
= kSecModDateItemAttr
; 
 393         if((CFDataGetLength(label
) == sizeof(SecKeychainAttrType
)) && 
 394                 ((memcmp(CFDataGetBytePtr(label
), &cdat
, sizeof(SecKeychainAttrType
)) == 0) || 
 395                  (memcmp(CFDataGetBytePtr(label
), &cmod
, sizeof(SecKeychainAttrType
)) == 0))) { 
 399         // Collect the raw data for each value of this CssmDbAttributeData 
 400         CFRef
<CFMutableArrayRef
> attributeDataContainer
; 
 401         attributeDataContainer
.take(CFArrayCreateMutable(NULL
, data
.size(), &kCFTypeArrayCallBacks
)); 
 403         for(int j 
= 0; j 
< data
.size(); j
++) { 
 404             CssmData
& entry 
= data
.values()[j
]; 
 406             CFRef
<CFDataRef
> datadata 
= NULL
; 
 407             switch(actualInfo
.format()) { 
 408                 case CSSM_DB_ATTRIBUTE_FORMAT_BLOB
: 
 409                 case CSSM_DB_ATTRIBUTE_FORMAT_STRING
: 
 410                 case CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE
: 
 411                     datadata
.take(CFDataCreate(NULL
, reinterpret_cast<const UInt8
*>(data
.values()[j
].data()), data
.values()[j
].length())); 
 414                 case CSSM_DB_ATTRIBUTE_FORMAT_UINT32
: { 
 415                     uint32 x 
= entry
.length() == 1 ? *reinterpret_cast<uint8 
*>(entry
.Data
) : 
 416                                entry
.length() == 2 ? *reinterpret_cast<uint16 
*>(entry
.Data
) : 
 417                                entry
.length() == 4 ? *reinterpret_cast<uint32 
*>(entry
.Data
) : 0; 
 418                     datadata
.take(CFDataCreate(NULL
, reinterpret_cast<const UInt8
*>(&x
), sizeof(x
))); 
 422                 case CSSM_DB_ATTRIBUTE_FORMAT_SINT32
: { 
 423                     sint32 x 
= entry
.length() == 1 ? *reinterpret_cast<sint8 
*>(entry
.Data
) : 
 424                                entry
.length() == 2 ? *reinterpret_cast<sint16 
*>(entry
.Data
) : 
 425                                entry
.length() == 4 ? *reinterpret_cast<sint32 
*>(entry
.Data
) : 0; 
 426                     datadata
.take(CFDataCreate(NULL
, reinterpret_cast<const UInt8
*>(&x
), sizeof(x
))); 
 429                 // CSSM_DB_ATTRIBUTE_FORMAT_BIG_NUM is unimplemented here but 
 430                 // has some canonicalization requirements, see DbValue.cpp 
 436             CFArrayAppendValue(attributeDataContainer
, datadata
); 
 438         CFDictionaryAddValue(attributes
, label
, attributeDataContainer
); 
 441     // Now that we have a CFDictionary containing a bunch of CFDatas, turn that 
 445     CFRef
<CFDataRef
> derBlob
; 
 446     derBlob
.take(CFPropertyListCreateDERData(NULL
, attributes
, &error
)); 
 448     // TODO: How do we check error here? 
 454     attributeBlob
.length(CFDataGetLength(derBlob
)); 
 455     attributeBlob
.copy(CFDataGetBytePtr(derBlob
), CFDataGetLength(derBlob
)); 
 458 void ItemImpl::computeDigest(CssmOwnedData 
&sha2
) { 
 459     auto_ptr
<DbAttributes
> dbAttributes(getCurrentAttributes()); 
 460     ItemImpl::computeDigestFromDictionary(sha2
, dbAttributes
.get()); 
 463 void ItemImpl::computeDigestFromDictionary(CssmOwnedData 
&sha2
, DbAttributes
* dbAttributes
) { 
 465         CssmAutoData 
attributeBlob(Allocator::standard()); 
 466         encodeAttributesFromDictionary(attributeBlob
, dbAttributes
); 
 468         sha2
.length(CC_SHA256_DIGEST_LENGTH
); 
 469         CC_SHA256(attributeBlob
.get().data(), static_cast<CC_LONG
>(attributeBlob
.get().length()), sha2
); 
 470         secinfo("integrity", "finished: %s", sha2
.get().toHex().c_str()); 
 471     } catch (MacOSError mose
) { 
 472         secnotice("integrity", "MacOSError: %d", (int)mose
.osStatus()); 
 474         secnotice("integrity", "unknown exception"); 
 478 void ItemImpl::addIntegrity(Access 
&access
, bool force
) { 
 479     if(!force 
&& (!mKeychain 
|| !mKeychain
->hasIntegrityProtection())) { 
 480         secinfo("integrity", "skipping integrity add due to keychain version\n"); 
 485     CssmAutoData 
digest(Allocator::standard()); 
 486     computeDigest(digest
); 
 488     // First, check if this already has an integrity tag 
 490     access
.findSpecificAclsForRight(CSSM_ACL_AUTHORIZATION_INTEGRITY
, acls
); 
 492     if(acls
.size() >= 1) { 
 493         // Use the existing ACL 
 495         secinfo("integrity", "previous integrity acl exists; setting integrity"); 
 496         acl
->setIntegrity(digest
.get()); 
 498         // Delete all extra ACLs 
 499         for(int i 
= 1; i 
< acls
.size(); i
++) { 
 500             secnotice("integrity", "extra integrity acls exist; removing %d",i
); 
 503     } else if(acls
.size() == 0) { 
 505         secnotice("integrity", "no previous integrity acl exists; making a new one"); 
 506         acl 
= new ACL(digest
.get()); 
 511  void ItemImpl::setIntegrity(bool force
) { 
 512      if(!force 
&& (!mKeychain 
|| !mKeychain
->hasIntegrityProtection())) { 
 513          secnotice("integrity", "skipping integrity set due to keychain version"); 
 517      // For Items, only passwords should have integrity 
 518      if(!(recordType() == CSSM_DL_DB_RECORD_GENERIC_PASSWORD 
|| recordType() == CSSM_DL_DB_RECORD_INTERNET_PASSWORD
)) { 
 522      // If we're not on an SSDb, we shouldn't have integrity 
 523      Db 
db(mKeychain
->database()); 
 524      if (!useSecureStorage(db
)) { 
 528      setIntegrity(*group(), force
); 
 531 void ItemImpl::setIntegrity(AclBearer 
&bearer
, bool force
) { 
 532     if(!force 
&& (!mKeychain 
|| !mKeychain
->hasIntegrityProtection())) { 
 533         secnotice("integrity", "skipping integrity acl set due to keychain version"); 
 537     SecPointer
<Access
> access 
= new Access(bearer
); 
 539     access
->removeAclsForRight(CSSM_ACL_AUTHORIZATION_PARTITION_ID
); 
 540     addIntegrity(*access
, force
); 
 541     access
->setAccess(bearer
, true); 
 544 void ItemImpl::removeIntegrity(const AccessCredentials 
*cred
) { 
 545     removeIntegrity(*group(), cred
); 
 548 void ItemImpl::removeIntegrity(AclBearer 
&bearer
, const AccessCredentials 
*cred
) { 
 549     SecPointer
<Access
> access 
= new Access(bearer
); 
 552     access
->findSpecificAclsForRight(CSSM_ACL_AUTHORIZATION_INTEGRITY
, acls
); 
 553     for(int i 
= 0; i 
< acls
.size(); i
++) { 
 557     access
->findSpecificAclsForRight(CSSM_ACL_AUTHORIZATION_PARTITION_ID
, acls
); 
 558     for(int i 
= 0; i 
< acls
.size(); i
++) { 
 562     access
->editAccess(bearer
, true, cred
); 
 565 bool ItemImpl::checkIntegrity() { 
 566     // Note: subclasses are responsible for checking themselves. 
 568     // If we don't have a keychain yet, we don't have any group. Return true? 
 569     if(!isPersistent()) { 
 570         secnotice("integrity", "no keychain, integrity is valid?"); 
 574     if(!mKeychain 
|| !mKeychain
->hasIntegrityProtection()) { 
 575         secinfo("integrity", "skipping integrity check due to keychain version"); 
 579     // Collect our SSGroup, if it exists. 
 581     SSGroup ssGroup 
= group(); 
 583         return checkIntegrity(*ssGroup
); 
 586     // If we don't have an SSGroup, we can't be invalid. return true. 
 590 bool ItemImpl::checkIntegrity(AclBearer
& aclBearer
) { 
 591     if(!mKeychain 
|| !mKeychain
->hasIntegrityProtection()) { 
 592         secinfo("integrity", "skipping integrity check due to keychain version"); 
 596     auto_ptr
<DbAttributes
> dbAttributes(getCurrentAttributes()); 
 597     return checkIntegrityFromDictionary(aclBearer
, dbAttributes
.get()); 
 600 bool ItemImpl::checkIntegrityFromDictionary(AclBearer
& aclBearer
, DbAttributes
* dbAttributes
) { 
 602         AutoAclEntryInfoList aclInfos
; 
 603         aclBearer
.getAcl(aclInfos
, CSSM_APPLE_ACL_TAG_INTEGRITY
); 
 605         // We should only expect there to be one integrity tag. If there's not, 
 606         // take the first one and ignore the rest. We should probably attempt delete 
 609         AclEntryInfo 
&info 
= aclInfos
.at(0); 
 610         auto_ptr
<ACL
> acl(new ACL(info
, Allocator::standard())); 
 612         for(int i 
= 1; i 
< aclInfos
.count(); i
++) { 
 613             secnotice("integrity", "*** DUPLICATE INTEGRITY ACL, something has gone wrong"); 
 616         CssmAutoData 
digest(Allocator::standard()); 
 617         computeDigestFromDictionary(digest
, dbAttributes
); 
 618         if (acl
->integrity() == digest
.get()) { 
 622     catch (CssmError cssme
) { 
 623         const char* errStr 
= cssmErrorString(cssme
.error
); 
 624         secnotice("integrity", "caught CssmError: %d %s", (int) cssme
.error
, errStr
); 
 626         if(cssme
.error 
== CSSMERR_CSP_ACL_ENTRY_TAG_NOT_FOUND
) { 
 627             // TODO: No entry, run migrator? 
 630         if(cssme
.error 
== CSSMERR_CSP_INVALID_ACL_SUBJECT_VALUE
) { 
 631             // something went horribly wrong with fetching acl. 
 633             secnotice("integrity", "INVALID ITEM (too many integrity acls)"); 
 636         if(cssme
.error 
== CSSMERR_CSP_VERIFY_FAILED
) { 
 637             secnotice("integrity", "MAC verification failed; something has gone very wrong"); 
 638             return false; // No MAC, no integrity. 
 644     secnotice("integrity", "***** INVALID ITEM"); 
 648 PrimaryKey 
ItemImpl::addWithCopyInfo (Keychain 
&keychain
, bool isCopy
) 
 650         StLock
<Mutex
>_(mMutex
); 
 651         // If we already have a Keychain we can't be added. 
 653                 MacOSError::throwMe(errSecDuplicateItem
); 
 655     // If we don't have any attributes we can't be added. 
 656     // (this might occur if attempting to add the item twice, since our attributes 
 657     // and data are set to NULL at the end of this function.) 
 658     if (!mDbAttributes
.get()) 
 659                 MacOSError::throwMe(errSecDuplicateItem
); 
 661         CSSM_DB_RECORDTYPE recordType 
= mDbAttributes
->recordType(); 
 663         // update the creation and update dates on the new item 
 666                 KeychainSchema schema 
= keychain
->keychainSchema(); 
 668                 GetCurrentMacLongDateTime(date
); 
 669                 if (schema
->hasAttribute(recordType
, kSecCreationDateItemAttr
)) 
 671                         setAttribute(schema
->attributeInfoFor(recordType
, kSecCreationDateItemAttr
), date
); 
 674                 if (schema
->hasAttribute(recordType
, kSecModDateItemAttr
)) 
 676                         setAttribute(schema
->attributeInfoFor(recordType
, kSecModDateItemAttr
), date
); 
 680     // If the label (PrintName) attribute isn't specified, set a default label. 
 681     mDbAttributes
->canonicalize(); // make sure we'll find the label with the thing Schema::attributeInfo returns 
 682     if (!mDoNotEncrypt 
&& !mDbAttributes
->find(Schema::attributeInfo(kSecLabelItemAttr
))) 
 684                 // if doNotEncrypt was set all of the attributes are wrapped in the data blob.  Don't calculate here. 
 685         CssmDbAttributeData 
*label 
= NULL
; 
 688             case CSSM_DL_DB_RECORD_GENERIC_PASSWORD
: 
 689                 label 
= mDbAttributes
->find(Schema::attributeInfo(kSecServiceItemAttr
)); 
 692             case CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD
: 
 693             case CSSM_DL_DB_RECORD_INTERNET_PASSWORD
: 
 694                 label 
= mDbAttributes
->find(Schema::attributeInfo(kSecServerItemAttr
)); 
 695                 // if AppleShare server name wasn't specified, try the server address 
 696                 if (!label
) label 
= mDbAttributes
->find(Schema::attributeInfo(kSecAddressItemAttr
)); 
 702         // if all else fails, use the account name. 
 704                         label 
= mDbAttributes
->find(Schema::attributeInfo(kSecAccountItemAttr
)); 
 706         if (label 
&& label
->size()) 
 707             setAttribute (Schema::attributeInfo(kSecLabelItemAttr
), label
->at
<CssmData
>(0)); 
 710         // get the attributes that are part of the primary key 
 711         const CssmAutoDbRecordAttributeInfo 
&primaryKeyInfos 
= 
 712                 keychain
->primaryKeyInfosFor(recordType
); 
 714         // make sure each primary key element has a value in the item, otherwise 
 715         // the database will complain. we make a set of the provided attribute infos 
 716         // to avoid O(N^2) behavior. 
 718         DbAttributes 
*attributes 
= mDbAttributes
.get(); 
 719         typedef set
<CssmDbAttributeInfo
> InfoSet
; 
 724                 // make a set of all the attributes in the key 
 725                 for (uint32 i 
= 0; i 
< attributes
->size(); i
++) 
 726                         infoSet
.insert(attributes
->at(i
).Info
); 
 728                 for (uint32 i 
= 0; i 
< primaryKeyInfos
.size(); i
++) { // check to make sure all required attributes are in the key 
 729                         InfoSet::const_iterator it 
= infoSet
.find(primaryKeyInfos
.at(i
)); 
 731                         if (it 
== infoSet
.end()) { // not in the key?  add the default 
 732                                 // we need to add a default value to the item attributes 
 733                                 attributes
->add(primaryKeyInfos
.at(i
), defaultAttributeValue(primaryKeyInfos
.at(i
))); 
 739         mKeychain 
= keychain
; 
 740         StLock
<Mutex
>_(*(mKeychain
->getKeychainMutex())); // must hold this mutex before calling db->insert 
 742         Db 
db(keychain
->database()); 
 745             mUniqueId 
= db
->insertWithoutEncryption (recordType
, NULL
, mData
.get()); 
 747         else if (useSecureStorage(db
)) 
 749             updateSSGroup(db
, recordType
, mData
.get(), keychain
, mAccess
); 
 750             mAccess 
= NULL
; // use them and lose them - TODO: should this only be unset if there's no error in saveToNewSSGroup? Unclear. 
 754             // add the item to the (regular) db 
 755             mUniqueId 
= db
->insert(recordType
, mDbAttributes
.get(), mData
.get()); 
 758         mPrimaryKey 
= keychain
->makePrimaryKey(recordType
, mUniqueId
); 
 764         // Forget our data and attributes. 
 766         mDbAttributes
.reset(NULL
); 
 774 ItemImpl::add (Keychain 
&keychain
) 
 776         return addWithCopyInfo (keychain
, false); 
 782 ItemImpl::copyTo(const Keychain 
&keychain
, Access 
*newAccess
) 
 784     // We'll be removing any Partition or Integrity ACLs from this item during 
 785     // the copy. Note that creating a new item from this one fetches the data, 
 786     // so this process must now be on the ACL/partition ID list for this item, 
 787     // and an attacker without access can't cause this removal. 
 789     // The integrity and partition ID acls will get re-added once the item lands 
 790     // in the new keychain, if it supports them. If it doesn't, removing the 
 791     // integrity acl as it leaves will prevent any issues if the item is 
 792     // modified in the unsupported keychain and then re-copied back into an 
 793     // integrity keychain. 
 795         StLock
<Mutex
>_(mMutex
); 
 798         newAccess
->removeAclsForRight(CSSM_ACL_AUTHORIZATION_PARTITION_ID
); 
 799         newAccess
->removeAclsForRight(CSSM_ACL_AUTHORIZATION_INTEGRITY
); 
 800                 item
->setAccess(newAccess
); 
 802                 /* Attempt to copy the access from the current item to the newly created one. */ 
 803                 SSGroup myGroup 
= group(); 
 806                         SecPointer
<Access
> access 
= new Access(*myGroup
); 
 807             access
->removeAclsForRight(CSSM_ACL_AUTHORIZATION_PARTITION_ID
); 
 808             access
->removeAclsForRight(CSSM_ACL_AUTHORIZATION_INTEGRITY
); 
 809                         item
->setAccess(access
); 
 813         keychain
->addCopy(item
); 
 820         StLock
<Mutex
>_(mMutex
); 
 822                 MacOSError::throwMe(errSecNoSuchKeychain
); 
 824         // Don't update if nothing changed. 
 828     // Hold this before modifying the db below 
 829     StLock
<Mutex
>__(*(mKeychain
->getKeychainMutex())); 
 831         CSSM_DB_RECORDTYPE aRecordType 
= recordType(); 
 832         KeychainSchema schema 
= mKeychain
->keychainSchema(); 
 834         // Update the modification date on the item if there is a mod date attribute. 
 835         if (schema
->hasAttribute(aRecordType
, kSecModDateItemAttr
)) 
 838                 GetCurrentMacLongDateTime(date
); 
 839                 setAttribute(schema
->attributeInfoFor(aRecordType
, kSecModDateItemAttr
), date
); 
 842         Db 
db(dbUniqueRecord()->database()); 
 845                 CSSM_DB_RECORD_ATTRIBUTE_DATA attrData
; 
 846                 memset (&attrData
, 0, sizeof (attrData
)); 
 847                 attrData
.DataRecordType 
= aRecordType
; 
 849                 dbUniqueRecord()->modifyWithoutEncryption(aRecordType
, 
 852                                                   CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
); 
 854         else if (useSecureStorage(db
)) 
 856         // Pass mData to updateSSGroup. If we have any data to change (and it's 
 857         // therefore non-null), it'll save to a new SSGroup; otherwise, it will 
 858         // update the old ssgroup. This prevents a RAA on attribute update, while 
 859         // still protecting new data from being decrypted by old SSGroups with 
 860         // outdated attributes. 
 861         updateSSGroup(db
, recordType(), mData
.get()); 
 865                 dbUniqueRecord()->modify(aRecordType
, 
 868                                  CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
); 
 873                 PrimaryKey oldPK 
= mPrimaryKey
; 
 874                 mPrimaryKey 
= mKeychain
->makePrimaryKey(aRecordType
, mUniqueId
); 
 876                 // Forget our data and attributes. 
 878                 mDbAttributes
.reset(NULL
); 
 880                 // Let the Keychain update what it needs to. 
 881                 mKeychain
->didUpdate(this, oldPK
, mPrimaryKey
); 
 886 ItemImpl::updateSSGroup(Db
& db
, CSSM_DB_RECORDTYPE recordType
, CssmDataContainer
* newdata
, Keychain keychain
, SecPointer
<Access
> access
) 
 888     // hhs replaced with the new aclFactory class 
 889     AclFactory aclFactory
; 
 890     const AccessCredentials 
*nullCred 
= aclFactory
.nullCred(); 
 892     bool haveOldUniqueId 
= !!mUniqueId
.get(); 
 893     SSDbUniqueRecord 
ssUniqueId(NULL
); 
 894     SSGroup 
ssGroup(NULL
); 
 895     if(haveOldUniqueId
) { 
 896         ssUniqueId 
= SSDbUniqueRecord(dynamic_cast<SSDbUniqueRecordImpl 
*>(&(*mUniqueId
))); 
 897         if (ssUniqueId
.get() == NULL
) { 
 898             CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
); 
 900         ssGroup 
= ssUniqueId
->group(); 
 903     // If we have new data OR no old unique id, save to a new group 
 904     bool saveToNewSSGroup 
= (!!newdata
) || (!haveOldUniqueId
); 
 906     // If there aren't any attributes, make up some blank ones. 
 907     if (!mDbAttributes
.get()) 
 909         secinfo("integrity", "making new dbattributes"); 
 910         mDbAttributes
.reset(new DbAttributes()); 
 911         mDbAttributes
->recordType(mPrimaryKey
->recordType()); 
 914     // Add the item to the secure storage db 
 915     SSDbImpl
* impl 
= dynamic_cast<SSDbImpl 
*>(&(*db
)); 
 918         CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
); 
 923     TrackingAllocator 
allocator(Allocator::standard()); 
 925     if ((!access
) && (haveOldUniqueId
)) { 
 926         // Copy the ACL from the old group. 
 927         secinfo("integrity", "copying old ACL"); 
 928         access 
= new Access(*(ssGroup
)); 
 930         // We can't copy these over to the new item; they're going to be reset. 
 931         // Remove them before securityd complains. 
 932         access
->removeAclsForRight(CSSM_ACL_AUTHORIZATION_PARTITION_ID
); 
 933         access
->removeAclsForRight(CSSM_ACL_AUTHORIZATION_INTEGRITY
); 
 934     } else if (!access
) { 
 935         secinfo("integrity", "setting up new ACL"); 
 936         // create default access controls for the new item 
 937         CssmDbAttributeData 
*data 
= mDbAttributes
->find(Schema::attributeInfo(kSecLabelItemAttr
)); 
 938         string printName 
= data 
? CssmData::overlay(data
->Value
[0]).toString() : "keychain item"; 
 939         access 
= new Access(printName
); 
 941         secinfo("integrity", "passed an Access, use it"); 
 942         // Access is non-null. Do nothing. 
 945     // If we have an old group and an old mUniqueId, then we're in the middle of an update. 
 946     // mDbAttributes contains the newest attributes, but not the old ones. Find 
 947     // them, merge them, and shove them all back into mDbAttributes. This lets 
 948     // us re-apply them all to the new item. 
 949     if(haveOldUniqueId
) { 
 950         mDbAttributes
.reset(getCurrentAttributes()); 
 953     // Create a CSPDL transaction. Note that this does things when it goes out of scope. 
 954     CSPDLTransaction 
transaction(db
); 
 957     ResourceControlContext prototype
; 
 958     maker
.initialOwner(prototype
, nullCred
); 
 960     if(saveToNewSSGroup
) { 
 961         secinfo("integrity", "saving to a new SSGroup"); 
 963         // If we're updating an item, it has an old group and possibly an 
 964         // old mUniqueId. Delete these from the database, so we can insert 
 966         if(haveOldUniqueId
) { 
 967             secinfo("integrity", "deleting old mUniqueId"); 
 968             mUniqueId
->deleteRecord(); 
 971             secinfo("integrity", "no old mUniqueId"); 
 974         // Create a new SSGroup with temporary access controls 
 975         SSGroup 
newSSGroup(ssDb
, &prototype
); 
 976         const AccessCredentials 
* cred 
= maker
.cred(); 
 979             doChange(keychain
, recordType
, ^{ 
 980                 mUniqueId 
= ssDb
->ssInsert(recordType
, mDbAttributes
.get(), newdata
, newSSGroup
, cred
); 
 983             // now finalize the access controls on the group 
 984             addIntegrity(*access
); 
 985             access
->setAccess(*newSSGroup
, maker
); 
 987             // We have to reset this after we add the integrity, since it needs the attributes 
 988             mDbAttributes
.reset(NULL
); 
 990             transaction
.commit(); 
 992         catch (CssmError cssme
) { 
 993             const char* errStr 
= cssmErrorString(cssme
.error
); 
 994             secnotice("integrity", "caught CssmError during add: %d %s", (int) cssme
.error
, errStr
); 
 996             // Delete the new SSGroup that we just created 
 997             deleteSSGroup(newSSGroup
, nullCred
); 
1000         catch (MacOSError mose
) { 
1001             secnotice("integrity", "caught MacOSError during add: %d", (int) mose
.osStatus()); 
1003             deleteSSGroup(newSSGroup
, nullCred
); 
1008             secnotice("integrity", "caught unknown exception during add"); 
1010             deleteSSGroup(newSSGroup
, nullCred
); 
1014         // Modify the old SSGroup 
1015         secinfo("integrity", "modifying the existing SSGroup"); 
1018             doChange(keychain
, recordType
, ^{ 
1020                 const AccessCredentials 
*autoPrompt 
= globals().itemCredentials(); 
1021                 ssUniqueId
->modify(recordType
, 
1022                         mDbAttributes
.get(), 
1024                         CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
, 
1028             // Update the integrity on the SSGroup 
1029             setIntegrity(*ssGroup
); 
1031             // We have to reset this after we add the integrity, since it needs the attributes 
1032             mDbAttributes
.reset(NULL
); 
1034             transaction
.commit(); 
1036         catch (CssmError cssme
) { 
1037             const char* errStr 
= cssmErrorString(cssme
.error
); 
1038             secnotice("integrity", "caught CssmError during modify: %d %s", (int) cssme
.error
, errStr
); 
1041         catch (MacOSError mose
) { 
1042             secnotice("integrity", "caught MacOSError during modify: %d", (int) mose
.osStatus()); 
1047             secnotice("integrity", "caught unknown exception during modify"); 
1054 // Helper function to delete a group and swallow all errors 
1055 void ItemImpl::deleteSSGroup(SSGroup 
& ssgroup
, const AccessCredentials
* nullCred
) { 
1057         ssgroup
->deleteKey(nullCred
); 
1058     } catch(CssmError error
) { 
1059         secnotice("integrity", "caught cssm error during deletion of group: %d %s", (int) error
.osStatus(), error
.what()); 
1060     } catch(MacOSError error
) { 
1061         secnotice("integrity", "caught macos error during deletion of group: %d %s", (int) error
.osStatus(), error
.what()); 
1062     } catch(UnixError error
) { 
1063         secnotice("integrity", "caught unix error during deletion of group: %d %s", (int) error
.osStatus(), error
.what()); 
1068 ItemImpl::doChange(Keychain keychain
, CSSM_DB_RECORDTYPE recordType
, void (^tryChange
) ()) 
1070     // Insert the record using the newly created group. 
1073     } catch (CssmError cssme
) { 
1074         // If there's a "duplicate" of this item, it might be an item with corrupt/invalid attributes 
1075         // Try to extract the item and check its attributes, then try again if necessary 
1076         auto_ptr
<CssmClient::DbAttributes
> primaryKeyAttrs
; 
1077         if(cssme
.error 
== CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA
) { 
1078             secnotice("integrity", "possible duplicate, trying to delete invalid items"); 
1080             Keychain kc 
= (keychain 
? keychain 
: mKeychain
); 
1082                 secnotice("integrity", "no valid keychain"); 
1085             // Only check for corrupt items if the keychain supports them 
1086             if((!kc
) || !kc
->hasIntegrityProtection()) { 
1087                 secinfo("integrity", "skipping integrity check for corrupt items due to keychain support"); 
1090                 primaryKeyAttrs
.reset(getCurrentAttributes()); 
1091                 PrimaryKey pk 
= kc
->makePrimaryKey(recordType
, primaryKeyAttrs
.get()); 
1093                 bool tryAgain 
= false; 
1095                 // Because things are lazy, maybe our keychain has a version 
1096                 // of this item with different attributes. Ask it! 
1097                 ItemImpl
* maybeItem 
= kc
->_lookupItem(pk
); 
1099                     if(!maybeItem
->checkIntegrity()) { 
1100                         Item 
item(maybeItem
); 
1101                         kc
->deleteItem(item
); 
1105                     // Our keychain doesn't know about any item with this primary key, so maybe 
1106                     // we have a corrupt item in the database. Let's check. 
1108                     secinfo("integrity", "making a cursor from primary key"); 
1109                     CssmClient::DbCursor cursor 
= pk
->createCursor(kc
); 
1110                     DbUniqueRecord uniqueId
; 
1112                     StLock
<Mutex
> _mutexLocker(*kc
->getKeychainMutex()); 
1114                     // The item on-disk might have more or different attributes than we do, since we're 
1115                     // only searching via primary key. Fetch all of its attributes. 
1116                     auto_ptr
<DbAttributes
>dbDupAttributes (new DbAttributes(kc
->database(), 1)); 
1117                     fillDbAttributesFromSchema(*dbDupAttributes
, recordType
, kc
); 
1119                     // Occasionally this cursor won't return the item attributes (for an unknown reason). 
1120                     // However, we know the attributes any item with this primary key should have, so use those instead. 
1121                     while (cursor
->next(dbDupAttributes
.get(), NULL
, uniqueId
)) { 
1122                         secinfo("integrity", "got an item..."); 
1124                         SSGroup group 
= safer_cast
<SSDbUniqueRecordImpl 
&>(*uniqueId
).group(); 
1125                         if(!ItemImpl::checkIntegrityFromDictionary(*group
, dbDupAttributes
.get())) { 
1126                             secnotice("integrity", "item is invalid! deleting..."); 
1127                             uniqueId
->deleteRecord(); 
1134                     secnotice("integrity", "trying again..."); 
1137                     // We didn't find an invalid item, the duplicate item exception is real 
1138                     secnotice("integrity", "duplicate item exception is real; throwing it on"); 
1149 ItemImpl::getClass(SecKeychainAttribute 
&attr
, UInt32 
*actualLength
) 
1151         StLock
<Mutex
>_(mMutex
); 
1153                 *actualLength 
= sizeof(SecItemClass
); 
1155         if (attr
.length 
< sizeof(SecItemClass
)) 
1156                 MacOSError::throwMe(errSecBufferTooSmall
); 
1158         SecItemClass aClass 
= Schema::itemClassFor(recordType()); 
1159         memcpy(attr
.data
, &aClass
, sizeof(SecItemClass
)); 
1163 ItemImpl::setAttribute(SecKeychainAttribute
& attr
) 
1165         StLock
<Mutex
>_(mMutex
); 
1166     setAttribute(Schema::attributeInfo(attr
.tag
), CssmData(attr
.data
, attr
.length
)); 
1170 ItemImpl::recordType() 
1172         StLock
<Mutex
>_(mMutex
); 
1173         if (mDbAttributes
.get()) 
1174                 return mDbAttributes
->recordType(); 
1176         return mPrimaryKey
->recordType(); 
1179 const DbAttributes 
* 
1180 ItemImpl::modifiedAttributes() 
1182         StLock
<Mutex
>_(mMutex
); 
1183         return mDbAttributes
.get(); 
1187 ItemImpl::modifiedData() 
1189         StLock
<Mutex
>_(mMutex
); 
1194 ItemImpl::setData(UInt32 length
,const void *data
) 
1196         StLock
<Mutex
>_(mMutex
); 
1197         mData 
= new CssmDataContainer(data
, length
); 
1201 ItemImpl::setAccess(Access 
*newAccess
) 
1203         StLock
<Mutex
>_(mMutex
); 
1204         mAccess 
= newAccess
; 
1207 CssmClient::DbUniqueRecord
 
1208 ItemImpl::dbUniqueRecord() 
1210         StLock
<Mutex
>_(mMutex
); 
1211     if (!isPersistent()) // is there no database attached? 
1213         MacOSError::throwMe(errSecNotAvailable
); 
1218                 DbCursor 
cursor(mPrimaryKey
->createCursor(mKeychain
)); 
1219                 if (!cursor
->next(NULL
, NULL
, mUniqueId
)) 
1220                         MacOSError::throwMe(errSecInvalidItemRef
); 
1223     // Check that our Db still matches our keychain's db. If not, find this item again in the new Db. 
1224     // Why silly !(x == y) construction? Compiler calls operator bool() on each pointer otherwise. 
1225     if(!(mUniqueId
->database() == keychain()->database())) { 
1226         secinfo("integrity", "updating db of mUniqueRecord"); 
1228         DbCursor 
cursor(mPrimaryKey
->createCursor(mKeychain
)); 
1229         if (!cursor
->next(NULL
, NULL
, mUniqueId
)) 
1230             MacOSError::throwMe(errSecInvalidItemRef
); 
1237 ItemImpl::primaryKey() 
1243 ItemImpl::isPersistent() 
1249 ItemImpl::isModified() 
1251         StLock
<Mutex
>_(mMutex
); 
1252         return mData
.get() || mDbAttributes
.get(); 
1256 ItemImpl::keychain() 
1262 ItemImpl::operator < (const ItemImpl 
&other
) 
1264         if (mData 
&& *mData
) 
1267                 return this < &other
; 
1270         return mPrimaryKey 
< other
.mPrimaryKey
; 
1274 ItemImpl::setAttribute(const CssmDbAttributeInfo 
&info
, const CssmPolyData 
&data
) 
1276         StLock
<Mutex
>_(mMutex
); 
1277         if (!mDbAttributes
.get()) 
1279                 mDbAttributes
.reset(new DbAttributes()); 
1280                 mDbAttributes
->recordType(mPrimaryKey
->recordType()); 
1283         size_t length 
= data
.Length
; 
1284         const void *buf 
= reinterpret_cast<const void *>(data
.Data
); 
1285     uint8 timeString
[16]; 
1287     // XXX This code is duplicated in KCCursorImpl::KCCursorImpl() 
1288     // Convert a 4 or 8 byte TIME_DATE to a CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE 
1289     // style attribute value. 
1290     if (info
.format() == CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE
) 
1292         if (length 
== sizeof(UInt32
)) 
1294             MacSecondsToTimeString(*reinterpret_cast<const UInt32 
*>(buf
), 16, &timeString
); 
1298         else if (length 
== sizeof(SInt64
)) 
1300             MacLongDateTimeToTimeString(*reinterpret_cast<const SInt64 
*>(buf
), 16, &timeString
); 
1306         mDbAttributes
->add(info
, CssmData(const_cast<void*>(buf
), length
)); 
1310 ItemImpl::modifyContent(const SecKeychainAttributeList 
*attrList
, UInt32 dataLength
, const void *inData
) 
1312         StLock
<Mutex
>_(mMutex
); 
1313     StMaybeLock
<Mutex
>__ (mKeychain 
== NULL 
? NULL 
: mKeychain
->getKeychainMutex()); 
1315         if (!mDbAttributes
.get()) 
1317                 mDbAttributes
.reset(new DbAttributes()); 
1318                 mDbAttributes
->recordType(mPrimaryKey
->recordType()); 
1321         if(attrList
) // optional 
1323                 for(UInt32 ix
=0; ix 
< attrList
->count
; ix
++) 
1325             SecKeychainAttrType attrTag 
= attrList
->attr
[ix
].tag
; 
1327             if (attrTag 
== APPLEDB_CSSM_PRINTNAME_ATTRIBUTE
) 
1329                 // must remap a caller-supplied kSecKeyPrintName attribute tag for key items, since it isn't in the schema 
1330                 // (note that this will ultimately match kGenericPrintName in Schema.cpp) 
1331                 attrTag 
= kSecLabelItemAttr
; 
1334                         mDbAttributes
->add(Schema::attributeInfo(attrTag
), CssmData(attrList
->attr
[ix
].data
,  attrList
->attr
[ix
].length
)); 
1340                 mData 
= new CssmDataContainer(inData
, dataLength
); 
1347 ItemImpl::getContent(SecItemClass 
*itemClass
, SecKeychainAttributeList 
*attrList
, UInt32 
*length
, void **outData
) 
1349         StLock
<Mutex
>_(mMutex
); 
1350     // If the data hasn't been set we can't return it. 
1351     if (!mKeychain 
&& outData
) 
1353                 CssmData 
*data 
= mData
.get(); 
1355                         MacOSError::throwMe(errSecDataNotAvailable
); 
1357     // TODO: need to check and make sure attrs are valid and handle error condition 
1361                 *itemClass 
= Schema::itemClassFor(recordType()); 
1363     bool getDataFromDatabase 
= mKeychain 
&& mPrimaryKey
; 
1364     if (getDataFromDatabase
) // are we attached to a database? 
1368                 // get the number of attributes requested by the caller 
1369                 UInt32 attrCount 
= attrList 
? attrList
->count 
: 0; 
1371         // make a DBAttributes structure and populate it 
1372         DbAttributes 
dbAttributes(dbUniqueRecord()->database(), attrCount
); 
1373         for (UInt32 ix 
= 0; ix 
< attrCount
; ++ix
) 
1375             dbAttributes
.add(Schema::attributeInfo(attrList
->attr
[ix
].tag
)); 
1378         // request the data from the database (since we are a reference "item" and the data is really stored there) 
1379         CssmDataContainer itemData
; 
1380                 getContent(&dbAttributes
, outData 
? &itemData 
: NULL
); 
1382         // retrieve the data from result 
1383         for (UInt32 ix 
= 0; ix 
< attrCount
; ++ix
) 
1385             if (dbAttributes
.at(ix
).NumberOfValues 
> 0) 
1387                 attrList
->attr
[ix
].data 
= dbAttributes
.at(ix
).Value
[0].Data
; 
1388                 attrList
->attr
[ix
].length 
= (UInt32
)dbAttributes
.at(ix
).Value
[0].Length
; 
1390                 // We don't want the data released, it is up the client 
1391                 dbAttributes
.at(ix
).Value
[0].Data 
= NULL
; 
1392                 dbAttributes
.at(ix
).Value
[0].Length 
= 0; 
1396                 attrList
->attr
[ix
].data 
= NULL
; 
1397                 attrList
->attr
[ix
].length 
= 0; 
1404                         *outData
=itemData
.data(); 
1405                         itemData
.Data 
= NULL
; 
1408                                 *length
=(UInt32
)itemData
.length(); 
1409                         itemData
.Length 
= 0; 
1414                 getLocalContent(attrList
, length
, outData
); 
1419 ItemImpl::freeContent(SecKeychainAttributeList 
*attrList
, void *data
) 
1421     Allocator 
&allocator 
= Allocator::standard(Allocator::sensitive
); // @@@ This might not match the one used originally 
1423                 allocator
.free(data
); 
1425     UInt32 attrCount 
= attrList 
? attrList
->count 
: 0; 
1426     for (UInt32 ix 
= 0; ix 
< attrCount
; ++ix
) 
1428         allocator
.free(attrList
->attr
[ix
].data
); 
1429         attrList
->attr
[ix
].data 
= NULL
; 
1434 ItemImpl::modifyAttributesAndData(const SecKeychainAttributeList 
*attrList
, UInt32 dataLength
, const void *inData
) 
1436         StLock
<Mutex
>_(mMutex
); 
1438                 MacOSError::throwMe(errSecNoSuchKeychain
); 
1442                 if (!mDbAttributes
.get()) 
1444                         mDbAttributes
.reset(new DbAttributes()); 
1445                         mDbAttributes
->recordType(mPrimaryKey
->recordType()); 
1448                 CSSM_DB_RECORDTYPE recordType 
= mDbAttributes
->recordType(); 
1449                 UInt32 attrCount 
= attrList 
? attrList
->count 
: 0; 
1450                 for (UInt32 ix 
= 0; ix 
< attrCount
; ix
++) 
1452             SecKeychainAttrType attrTag 
= attrList
->attr
[ix
].tag
; 
1454             if (attrTag 
== kSecLabelItemAttr
) 
1456                 // must remap a caller-supplied label attribute tag for password items, since it isn't in the schema 
1457                 // (note that this will ultimately match kGenericPrintName in Schema.cpp) 
1458                 if (IS_PASSWORD_ITEM_CLASS( Schema::itemClassFor(recordType
) )) 
1459                     attrTag 
= APPLEDB_GENERIC_PRINTNAME_ATTRIBUTE
; 
1462             CssmDbAttributeInfo info
=mKeychain
->attributeInfoFor(recordType
, attrTag
); 
1464                         if (attrList
->attr
[ix
].length 
|| info
.AttributeFormat
==CSSM_DB_ATTRIBUTE_FORMAT_STRING  
|| info
.AttributeFormat
==CSSM_DB_ATTRIBUTE_FORMAT_BLOB
 
1465                          || info
.AttributeFormat
==CSSM_DB_ATTRIBUTE_FORMAT_STRING  
|| info
.AttributeFormat
==CSSM_DB_ATTRIBUTE_FORMAT_BIG_NUM
 
1466                          || info
.AttributeFormat
==CSSM_DB_ATTRIBUTE_FORMAT_MULTI_UINT32
) 
1467                                 mDbAttributes
->add(info
, CssmData(attrList
->attr
[ix
].data
, attrList
->attr
[ix
].length
)); 
1469                                 mDbAttributes
->add(info
); 
1475                 mData 
= new CssmDataContainer(inData
, dataLength
); 
1482 ItemImpl::getAttributesAndData(SecKeychainAttributeInfo 
*info
, SecItemClass 
*itemClass
, 
1483                                                            SecKeychainAttributeList 
**attrList
, UInt32 
*length
, void **outData
) 
1485         StLock
<Mutex
>_(mMutex
); 
1486         // If the data hasn't been set we can't return it. 
1487         if (!mKeychain 
&& outData
) 
1489                 CssmData 
*data 
= mData
.get(); 
1491                         MacOSError::throwMe(errSecDataNotAvailable
); 
1493         // TODO: need to check and make sure attrs are valid and handle error condition 
1495     SecItemClass myItemClass 
= Schema::itemClassFor(recordType()); 
1497                 *itemClass 
= myItemClass
; 
1499         // @@@ This call won't work for floating items (like certificates). 
1502     UInt32 attrCount 
= info 
? info
->count 
: 0; 
1503         DbAttributes 
dbAttributes(dbUniqueRecord()->database(), attrCount
); 
1504     for (UInt32 ix 
= 0; ix 
< attrCount
; ix
++) 
1506                 CssmDbAttributeData 
&record 
= dbAttributes
.add(); 
1507                 record
.Info
.AttributeNameFormat
=CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER
; 
1508                 record
.Info
.Label
.AttributeID
=info
->tag
[ix
]; 
1510         if (record
.Info
.Label
.AttributeID 
== kSecLabelItemAttr
) 
1512             // must remap a caller-supplied label attribute tag for password items, since it isn't in the schema 
1513             if (IS_PASSWORD_ITEM_CLASS( myItemClass 
)) 
1514                 record
.Info
.Label
.AttributeID 
= APPLEDB_GENERIC_PRINTNAME_ATTRIBUTE
; 
1518         CssmDataContainer itemData
; 
1519     getContent(&dbAttributes
, outData 
? &itemData 
: NULL
); 
1521         if (info 
&& attrList
) 
1523                 SecKeychainAttributeList 
*theList
=reinterpret_cast<SecKeychainAttributeList 
*>(malloc(sizeof(SecKeychainAttributeList
))); 
1525         if(attrCount 
== 0) { 
1527             theList
->attr 
= NULL
; 
1529             SecKeychainAttribute 
*attr
=reinterpret_cast<SecKeychainAttribute 
*>(malloc(sizeof(SecKeychainAttribute
)*attrCount
)); 
1530             theList
->count
=attrCount
; 
1533             for (UInt32 ix 
= 0; ix 
< attrCount
; ++ix
) 
1535                 attr
[ix
].tag
=info
->tag
[ix
]; 
1537                 if (dbAttributes
.at(ix
).NumberOfValues 
> 0) 
1539                     attr
[ix
].data 
= dbAttributes
.at(ix
).Value
[0].Data
; 
1540                     attr
[ix
].length 
= (UInt32
)dbAttributes
.at(ix
).Value
[0].Length
; 
1542                     // We don't want the data released, it is up the client 
1543                     dbAttributes
.at(ix
).Value
[0].Data 
= NULL
; 
1544                     dbAttributes
.at(ix
).Value
[0].Length 
= 0; 
1548                     attr
[ix
].data 
= NULL
; 
1549                     attr
[ix
].length 
= 0; 
1558                 *outData
=itemData
.data(); 
1561                 if (length
) *length
=(UInt32
)itemData
.length(); 
1568 ItemImpl::freeAttributesAndData(SecKeychainAttributeList 
*attrList
, void *data
) 
1570         Allocator 
&allocator 
= Allocator::standard(Allocator::sensitive
); // @@@ This might not match the one used originally 
1573                 allocator
.free(data
); 
1577                 for (UInt32 ix 
= 0; ix 
< attrList
->count
; ++ix
) 
1579                         allocator
.free(attrList
->attr
[ix
].data
); 
1581                 free(attrList
->attr
); 
1587 ItemImpl::getAttribute(SecKeychainAttribute
& attr
, UInt32 
*actualLength
) 
1589         StLock
<Mutex
>_(mMutex
); 
1590         if (attr
.tag 
== kSecClassItemAttr
) 
1591                 return getClass(attr
, actualLength
); 
1593         if (mDbAttributes
.get()) 
1595                 CssmDbAttributeData 
*data 
= mDbAttributes
->find(Schema::attributeInfo(attr
.tag
)); 
1598                         getAttributeFrom(data
, attr
, actualLength
); 
1604                 MacOSError::throwMe(errSecNoSuchAttr
); 
1606         DbAttributes 
dbAttributes(dbUniqueRecord()->database(), 1); 
1607         dbAttributes
.add(Schema::attributeInfo(attr
.tag
)); 
1608         dbUniqueRecord()->get(&dbAttributes
, NULL
); 
1609         getAttributeFrom(&dbAttributes
.at(0), attr
, actualLength
); 
1613 ItemImpl::getAttributeFrom(CssmDbAttributeData 
*data
, SecKeychainAttribute 
&attr
, UInt32 
*actualLength
) 
1615         StLock
<Mutex
>_(mMutex
); 
1616     static const uint32 zero 
= 0; 
1618     const void *buf 
= NULL
; 
1620     // Temporary storage for buf. 
1630     else if (data
->size() < 1) // Attribute has no values. 
1632         if (data
->format() == CSSM_DB_ATTRIBUTE_FORMAT_SINT32
 
1633             || data
->format() == CSSM_DB_ATTRIBUTE_FORMAT_UINT32
) 
1635             length 
= sizeof(zero
); 
1638         else if (data
->format() == CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE
) 
1639             length 
= 0; // Should we throw here? 
1640         else // All other formats 
1643     else // Get the first value 
1645         length 
= (UInt32
)data
->Value
[0].Length
; 
1646         buf 
= data
->Value
[0].Data
; 
1648         if (data
->format() == CSSM_DB_ATTRIBUTE_FORMAT_SINT32
) 
1650             if (attr
.length 
== sizeof(sint8
)) 
1652                 length 
= attr
.length
; 
1653                 svalue8 
= sint8(*reinterpret_cast<const sint32 
*>(buf
)); 
1656             else if (attr
.length 
== sizeof(sint16
)) 
1658                 length 
= attr
.length
; 
1659                 svalue16 
= sint16(*reinterpret_cast<const sint32 
*>(buf
)); 
1663         else if (data
->format() == CSSM_DB_ATTRIBUTE_FORMAT_UINT32
) 
1665             if (attr
.length 
== sizeof(uint8
)) 
1667                 length 
= attr
.length
; 
1668                 uvalue8 
= uint8(*reinterpret_cast<const uint32 
*>(buf
)); 
1671             else if (attr
.length 
== sizeof(uint16
)) 
1673                 length 
= attr
.length
; 
1674                 uvalue16 
= uint16(*reinterpret_cast<const uint32 
*>(buf
)); 
1678         else if (data
->format() == CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE
) 
1680             if (attr
.length 
== sizeof(uint32
)) 
1682                 TimeStringToMacSeconds(data
->Value
[0], macSeconds
); 
1684                 length 
= attr
.length
; 
1686             else if (attr
.length 
== sizeof(sint64
)) 
1688                 TimeStringToMacLongDateTime(data
->Value
[0], macLDT
); 
1690                 length 
= attr
.length
; 
1696                 *actualLength 
= length
; 
1700         if (attr
.length 
< length
) 
1701                         MacOSError::throwMe(errSecBufferTooSmall
); 
1703         memcpy(attr
.data
, buf
, length
); 
1708 ItemImpl::getData(CssmDataContainer
& outData
) 
1710         StLock
<Mutex
>_(mMutex
); 
1713                 CssmData 
*data 
= mData
.get(); 
1714                 // If the data hasn't been set we can't return it. 
1716                         MacOSError::throwMe(errSecDataNotAvailable
); 
1722     getContent(NULL
, &outData
); 
1728         StLock
<Mutex
>_(mMutex
); 
1732                 Db 
db(mKeychain
->database()); 
1733                 if (useSecureStorage(db
)) 
1735                         group 
= safer_cast
<SSDbUniqueRecordImpl 
&>(*dbUniqueRecord()).group(); 
1742 void ItemImpl::getLocalContent(SecKeychainAttributeList 
*attributeList
, UInt32 
*outLength
, void **outData
) 
1744         StLock
<Mutex
>_(mMutex
); 
1746     Allocator 
&allocator 
= Allocator::standard(); // @@@ This might not match the one used originally 
1749                 CssmData 
*data 
= mData
.get(); 
1751                         MacOSError::throwMe(errSecDataNotAvailable
); 
1753                 // Copy the data out of our internal cached copy. 
1754                 UInt32 length 
= (UInt32
)data
->Length
; 
1755                 *outData 
= allocator
.malloc(length
); 
1756                 memcpy(*outData
, data
->Data
, length
); 
1758                         *outLength 
= length
; 
1763                 if (!mDbAttributes
.get()) 
1764                         MacOSError::throwMe(errSecDataNotAvailable
); 
1766                 // Pull attributes out of a "floating" item, i.e. one that isn't attached to a database 
1767                 for (UInt32 ix 
= 0; ix 
< attributeList
->count
; ++ix
) 
1769                         SecKeychainAttribute 
&attribute 
= attributeList
->attr
[ix
]; 
1770                         CssmDbAttributeData 
*data 
= mDbAttributes
->find(Schema::attributeInfo(attribute
.tag
)); 
1771                         if (data 
&& data
->NumberOfValues 
> 0) 
1773                                 // Copy the data out of our internal cached copy. 
1774                                 UInt32 length 
= (UInt32
)data
->Value
[0].Length
; 
1775                                 attribute
.data 
= allocator
.malloc(length
); 
1776                                 memcpy(attribute
.data
, data
->Value
[0].Data
, length
); 
1777                                 attribute
.length 
= length
; 
1781                                 attribute
.length 
= 0; 
1782                                 attribute
.data 
= NULL
; 
1789 ItemImpl::getContent(DbAttributes 
*dbAttributes
, CssmDataContainer 
*itemData
) 
1791         StLock
<Mutex
>_(mMutex
); 
1794                 Db 
db(dbUniqueRecord()->database()); 
1797                         dbUniqueRecord()->getWithoutEncryption (dbAttributes
, itemData
); 
1800                 if (useSecureStorage(db
)) 
1803                 if(!checkIntegrity()) { 
1804                     secnotice("integrity", "item has no integrity, denying access"); 
1805                     CssmError::throwMe(errSecInvalidItemRef
); 
1807             } catch(CssmError cssme
) { 
1808                 secnotice("integrity", "error while checking integrity, denying access: %s", cssme
.what()); 
1812                         SSDbUniqueRecordImpl
* impl 
= dynamic_cast<SSDbUniqueRecordImpl 
*>(&(*dbUniqueRecord())); 
1815                                 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
); 
1818                         SSDbUniqueRecord 
ssUniqueId(impl
); 
1819                         const AccessCredentials 
*autoPrompt 
= globals().itemCredentials(); 
1820                         ssUniqueId
->get(dbAttributes
, itemData
, autoPrompt
); 
1825     dbUniqueRecord()->get(dbAttributes
, itemData
); 
1829 ItemImpl::useSecureStorage(const Db 
&db
) 
1831         StLock
<Mutex
>_(mMutex
); 
1832         switch (recordType()) 
1834         case CSSM_DL_DB_RECORD_GENERIC_PASSWORD
: 
1835         case CSSM_DL_DB_RECORD_INTERNET_PASSWORD
: 
1836         case CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD
: 
1837                 if (db
->dl()->subserviceMask() & CSSM_SERVICE_CSP
) 
1846 void ItemImpl::willRead() 
1850 Item 
ItemImpl::makeFromPersistentReference(const CFDataRef persistentRef
, bool *isIdentityRef
) 
1852         CssmData 
dictData((void*)::CFDataGetBytePtr(persistentRef
), ::CFDataGetLength(persistentRef
)); 
1853         NameValueDictionary 
dict(dictData
); 
1856         Item item 
= (ItemImpl 
*) NULL
; 
1858         if (isIdentityRef
) { 
1859                 *isIdentityRef 
= (dict
.FindByName(IDENTITY_KEY
) != 0) ? true : false; 
1862         // make sure we have a database identifier 
1863         if (dict
.FindByName(SSUID_KEY
) != 0) 
1865                 DLDbIdentifier dlDbIdentifier 
= NameValueDictionary::MakeDLDbIdentifierFromNameValueDictionary(dict
); 
1866                 DLDbIdentifier 
newDlDbIdentifier(dlDbIdentifier
.ssuid(), 
1867                                 DLDbListCFPref::ExpandTildesInPath(dlDbIdentifier
.dbName()).c_str(), 
1868                                 dlDbIdentifier
.dbLocation()); 
1870                 keychain 
= globals().storageManager
.keychain(newDlDbIdentifier
); 
1872                 const NameValuePair
* aDictItem 
= dict
.FindByName(ITEM_KEY
); 
1873                 if (aDictItem 
&& keychain
) 
1875                         PrimaryKey 
primaryKey(aDictItem
->Value()); 
1876                         item 
= keychain
->item(primaryKey
); 
1879         KCThrowIf_( !item
, errSecItemNotFound 
); 
1883 void ItemImpl::copyPersistentReference(CFDataRef 
&outDataRef
, bool isSecIdentityRef
) 
1885         if (secd_PersistentRef
) { 
1886                 outDataRef 
= secd_PersistentRef
; 
1889         StLock
<Mutex
>_(mMutex
); 
1890     // item must be in a keychain and have a primary key to be persistent 
1891     if (!mKeychain 
|| !mPrimaryKey
) { 
1892         MacOSError::throwMe(errSecItemNotFound
); 
1894     DLDbIdentifier dlDbIdentifier 
= mKeychain
->dlDbIdentifier(); 
1895     DLDbIdentifier 
newDlDbIdentifier(dlDbIdentifier
.ssuid(), 
1896         DLDbListCFPref::AbbreviatedPath(mKeychain
->name()).c_str(), 
1897         dlDbIdentifier
.dbLocation()); 
1898     NameValueDictionary dict
; 
1899     NameValueDictionary::MakeNameValueDictionaryFromDLDbIdentifier(newDlDbIdentifier
, dict
); 
1901     CssmData
* pKey 
= mPrimaryKey
; 
1902     dict
.Insert (new NameValuePair(ITEM_KEY
, *pKey
)); 
1904         if (isSecIdentityRef
) { 
1905                 uint32_t value 
= -1; 
1906                 CssmData 
valueData((void*)&value
, sizeof(value
)); 
1907                 dict
.Insert (new NameValuePair(IDENTITY_KEY
, valueData
)); 
1910     // flatten the NameValueDictionary 
1912     dict
.Export(dictData
); 
1913     outDataRef 
= ::CFDataCreate(kCFAllocatorDefault
, dictData
.Data
, dictData
.Length
); 
1914     free (dictData
.Data
); 
1917 void ItemImpl::copyRecordIdentifier(CSSM_DATA 
&data
) 
1919         StLock
<Mutex
>_(mMutex
); 
1920         CssmClient::DbUniqueRecord uniqueRecord 
= dbUniqueRecord (); 
1921         uniqueRecord
->getRecordIdentifier(data
); 
1925  * Obtain blob used to bind a keychain item to an Extended Attribute record. 
1926  * We just use the PrimaryKey blob as the default. Note that for standard Items, 
1927  * this can cause the loss of extended attribute bindings if a Primary Key 
1928  * attribute changes. 
1930 const CssmData 
&ItemImpl::itemID() 
1932         StLock
<Mutex
>_(mMutex
); 
1933         if(mPrimaryKey
->length() == 0) { 
1934                 /* not in a keychain; we don't have a primary key */ 
1935                 MacOSError::throwMe(errSecNoSuchAttr
); 
1937         return *mPrimaryKey
; 
1940 bool ItemImpl::equal(SecCFObject 
&other
) 
1942         // First check to see if both items have a primary key and 
1943         // if the primary key is the same.  If so then these 
1944         // items must be equal 
1945     ItemImpl
& other_item 
= (ItemImpl
&)other
; 
1946         if (mPrimaryKey 
!= NULL 
&& mPrimaryKey 
== other_item
.mPrimaryKey
) 
1951         // The primary keys do not match so do a CFHash of the 
1952         // data of the item and compare those for equality 
1953         CFHashCode this_hash 
= hash(); 
1954         CFHashCode other_hash 
= other
.hash(); 
1955         return (this_hash 
== other_hash
); 
1958 CFHashCode 
ItemImpl::hash() 
1960         CFHashCode result 
= SecCFObject::hash(); 
1962         StLock
<Mutex
>_(mMutex
); 
1963         RefPointer
<CssmDataContainer
> data_to_hash
; 
1965         // Use the item data for the hash 
1966         if (mData 
&& *mData
) 
1968                 data_to_hash 
= mData
; 
1971         // If there is no primary key AND not data ???? 
1972         // just return the 'old' hash value which is the 
1974         if (NULL 
!= data_to_hash
.get()) 
1976                 CFDataRef temp_data 
= NULL
; 
1977                 unsigned char digest
[CC_SHA256_DIGEST_LENGTH
]; 
1979                 if (data_to_hash
->length() < 80) 
1981                         // If it is less than 80 bytes then CFData can be used 
1982                         temp_data 
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, 
1983                                 (const UInt8 
*)data_to_hash
->data(), data_to_hash
->length(), kCFAllocatorNull
); 
1986                 // CFData truncates its hash value to 80 bytes. ???? 
1987                 // In order to do the 'right thing' a SHA 256 hash will be used to 
1988                 // include all of the data 
1991                         memset(digest
, 0, CC_SHA256_DIGEST_LENGTH
); 
1993                         CC_SHA256((const void *)data_to_hash
->data(), (CC_LONG
)data_to_hash
->length(), digest
); 
1995                         temp_data 
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, 
1996                                 (const UInt8 
*)digest
, CC_SHA256_DIGEST_LENGTH
, kCFAllocatorNull
); 
1999                 if (NULL 
!= temp_data
) 
2001                         result 
= CFHash(temp_data
); 
2002                         CFRelease(temp_data
); 
2011 void ItemImpl::postItemEvent(SecKeychainEvent theEvent
) 
2013         mKeychain
->postEvent(theEvent
, this); 
2019 // Item -- This class is here to magically create the right subclass of ItemImpl 
2020 // when constructing new items. 
2026 Item::Item(ItemImpl 
*impl
) : SecPointer
<ItemImpl
>(impl
) 
2030 Item::Item(SecItemClass itemClass
, OSType itemCreator
, UInt32 length
, const void* data
, bool inhibitCheck
) 
2034                 if (itemClass 
== CSSM_DL_DB_RECORD_X509_CERTIFICATE
 
2035                         || itemClass 
== CSSM_DL_DB_RECORD_PUBLIC_KEY
 
2036                         || itemClass 
== CSSM_DL_DB_RECORD_PRIVATE_KEY
 
2037                         || itemClass 
== CSSM_DL_DB_RECORD_SYMMETRIC_KEY
) 
2038                         MacOSError::throwMe(errSecNoSuchClass
); /* @@@ errSecInvalidClass */ 
2041         *this = new ItemImpl(itemClass
, itemCreator
, length
, data
, inhibitCheck
); 
2044 Item::Item(SecItemClass itemClass
, SecKeychainAttributeList 
*attrList
, UInt32 length
, const void* data
) 
2046         *this = new ItemImpl(itemClass
, attrList
, length
, data
); 
2049 Item::Item(const Keychain 
&keychain
, const PrimaryKey 
&primaryKey
, const CssmClient::DbUniqueRecord 
&uniqueId
) 
2050         : SecPointer
<ItemImpl
>( 
2051                 primaryKey
->recordType() == CSSM_DL_DB_RECORD_X509_CERTIFICATE
 
2052                 ? Certificate::make(keychain
, primaryKey
, uniqueId
) 
2053                 : (primaryKey
->recordType() == CSSM_DL_DB_RECORD_PUBLIC_KEY
 
2054                    || primaryKey
->recordType() == CSSM_DL_DB_RECORD_PRIVATE_KEY
 
2055                    || primaryKey
->recordType() == CSSM_DL_DB_RECORD_SYMMETRIC_KEY
) 
2056                 ? KeyItem::make(keychain
, primaryKey
, uniqueId
) 
2057                 : primaryKey
->recordType() == CSSM_DL_DB_RECORD_EXTENDED_ATTRIBUTE
 
2058                    ? ExtendedAttribute::make(keychain
, primaryKey
, uniqueId
) 
2059                    : ItemImpl::make(keychain
, primaryKey
, uniqueId
)) 
2063 Item::Item(const Keychain 
&keychain
, const PrimaryKey 
&primaryKey
) 
2064         : SecPointer
<ItemImpl
>( 
2065                 primaryKey
->recordType() == CSSM_DL_DB_RECORD_X509_CERTIFICATE
 
2066                 ? Certificate::make(keychain
, primaryKey
) 
2067                 : (primaryKey
->recordType() == CSSM_DL_DB_RECORD_PUBLIC_KEY
 
2068                    || primaryKey
->recordType() == CSSM_DL_DB_RECORD_PRIVATE_KEY
 
2069                    || primaryKey
->recordType() == CSSM_DL_DB_RECORD_SYMMETRIC_KEY
) 
2070                 ? KeyItem::make(keychain
, primaryKey
) 
2071                 : primaryKey
->recordType() == CSSM_DL_DB_RECORD_EXTENDED_ATTRIBUTE
 
2072                    ? ExtendedAttribute::make(keychain
, primaryKey
) 
2073                    : ItemImpl::make(keychain
, primaryKey
)) 
2077 Item::Item(ItemImpl 
&item
) 
2078         : SecPointer
<ItemImpl
>( 
2079                 item
.recordType() == CSSM_DL_DB_RECORD_X509_CERTIFICATE
 
2080                 ? new Certificate(safer_cast
<Certificate 
&>(item
)) 
2081                 : (item
.recordType() == CSSM_DL_DB_RECORD_PUBLIC_KEY
 
2082                    || item
.recordType() == CSSM_DL_DB_RECORD_PRIVATE_KEY
 
2083                    || item
.recordType() == CSSM_DL_DB_RECORD_SYMMETRIC_KEY
) 
2084                 ? new KeyItem(safer_cast
<KeyItem 
&>(item
)) 
2085                 : item
.recordType() == CSSM_DL_DB_RECORD_EXTENDED_ATTRIBUTE
 
2086                   ? new ExtendedAttribute(safer_cast
<ExtendedAttribute 
&>(item
)) 
2087                   : new ItemImpl(item
)) 
2091 CFIndex 
KeychainCore::GetItemRetainCount(Item
& item
) 
2093         return CFGetRetainCount(item
->handle(false)); 
2096 void ItemImpl::setPersistentRef(CFDataRef ref
) 
2098         if (secd_PersistentRef
) { 
2099                 CFRelease(secd_PersistentRef
); 
2101         secd_PersistentRef 
= ref
; 
2105 CFDataRef 
ItemImpl::getPersistentRef() 
2107         return secd_PersistentRef
; 
2112 bool ItemImpl::mayDelete() 
2114     ObjectImpl
* uniqueIDImpl 
= mUniqueId
.get(); 
2116     if (uniqueIDImpl 
!= NULL
) 
2118         bool result 
= mUniqueId
->isIdle();