2  * Copyright (c) 2002-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@ 
  27 #include <security_keychain/KeyItem.h> 
  28 #include <Security/cssmtype.h> 
  29 #include <security_keychain/Access.h> 
  30 #include <security_keychain/Keychains.h> 
  31 #include <security_keychain/KeyItem.h> 
  32 #include <security_cdsa_client/wrapkey.h> 
  33 #include <security_cdsa_client/genkey.h> 
  34 #include <security_cdsa_client/signclient.h> 
  35 #include <security_cdsa_client/cryptoclient.h> 
  36 #include <security_utilities/CSPDLTransaction.h> 
  38 #include <security_keychain/Globals.h> 
  39 #include "KCEventNotifier.h" 
  40 #include <CommonCrypto/CommonDigest.h> 
  41 #include <Security/SecBase.h> 
  42 #include <Security/SecBasePriv.h> 
  43 #include <CoreFoundation/CFPriv.h> 
  45 // @@@ This needs to be shared. 
  46 #pragma clang diagnostic push 
  47 #pragma clang diagnostic ignored "-Wunused-const-variable" 
  48 static CSSM_DB_NAME_ATTR(kInfoKeyPrintName
, kSecKeyPrintName
, (char*) "PrintName", 0, NULL
, BLOB
); 
  49 static CSSM_DB_NAME_ATTR(kInfoKeyLabel
, kSecKeyLabel
, (char*) "Label", 0, NULL
, BLOB
); 
  50 static CSSM_DB_NAME_ATTR(kInfoKeyApplicationTag
, kSecKeyApplicationTag
, (char*) "ApplicationTag", 0, NULL
, BLOB
); 
  51 #pragma clang diagnostic pop 
  53 using namespace KeychainCore
; 
  54 using namespace CssmClient
; 
  56 KeyItem 
*KeyItem::required(SecKeyRef ptr
) 
  58     if (KeyItem 
*p 
= optional(ptr
)) { 
  61         MacOSError::throwMe(errSecInvalidItemRef
); 
  65 KeyItem 
*KeyItem::optional(SecKeyRef ptr
) 
  68         if (KeyItem 
*pp 
= dynamic_cast<KeyItem 
*>(fromSecKeyRef(ptr
))) { 
  71             MacOSError::throwMe(errSecInvalidItemRef
); 
  78 KeyItem::operator CFTypeRef() const throw() 
  80     StMaybeLock
<Mutex
> _(this->getMutexForObject()); 
  82     if (mWeakSecKeyRef 
!= NULL
) { 
  83         if (_CFTryRetain(mWeakSecKeyRef
) == NULL
) { 
  84             StMaybeLock
<Mutex
> secKeyCDSAMutex(static_cast<CDSASecKey 
*>(mWeakSecKeyRef
)->cdsaKeyMutex
); 
  85             // mWeakSecKeyRef is not really valid, pointing to SecKeyRef which going to die - it is somewhere between last CFRelease and entering into mutex-protected section of SecCDSAKeyDestroy.  Avoid using it, pretend that no enveloping SecKeyRef exists.  But make sure that this KeyImpl is disconnected from this about-to-die SecKeyRef, because we do not want KeyImpl connected to it to be really destroyed, it will be connected to newly created SecKeyRef (see below). 
  86             mWeakSecKeyRef
->key 
= NULL
; 
  87             mWeakSecKeyRef 
= NULL
; 
  89             // We did not really want to retain, it was just weak->strong promotion test. 
  90             CFRelease(mWeakSecKeyRef
); 
  94     if (mWeakSecKeyRef 
== NULL
) { 
  95         // Create enveloping ref on-demand.  Transfer reference count from SecCFObject 
  96         // to newly created SecKeyRef wrapper. 
  99     return mWeakSecKeyRef
; 
 102 void KeyItem::initializeWithSecKeyRef(SecKeyRef ref
) 
 105     mWeakSecKeyRef 
= ref
; 
 109 KeyItem::KeyItem(const Keychain 
&keychain
, const PrimaryKey 
&primaryKey
, const CssmClient::DbUniqueRecord 
&uniqueId
) : 
 110         ItemImpl(keychain
, primaryKey
, uniqueId
), 
 113         mPubKeyHash(Allocator::standard()) 
 117 KeyItem::KeyItem(const Keychain 
&keychain
, const PrimaryKey 
&primaryKey
)  : 
 118         ItemImpl(keychain
, primaryKey
), 
 121         mPubKeyHash(Allocator::standard()) 
 125 KeyItem
* KeyItem::make(const Keychain 
&keychain
, const PrimaryKey 
&primaryKey
, const CssmClient::DbUniqueRecord 
&uniqueId
) 
 127         KeyItem
* k 
= new KeyItem(keychain
, primaryKey
, uniqueId
); 
 128         keychain
->addItem(primaryKey
, k
); 
 134 KeyItem
* KeyItem::make(const Keychain 
&keychain
, const PrimaryKey 
&primaryKey
) 
 136         KeyItem
* k 
= new KeyItem(keychain
, primaryKey
); 
 137         keychain
->addItem(primaryKey
, k
); 
 143 KeyItem::KeyItem(KeyItem 
&keyItem
) : 
 147         mPubKeyHash(Allocator::standard()) 
 149         // @@@ this doesn't work for keys that are not in a keychain. 
 152 KeyItem::KeyItem(const CssmClient::Key 
&key
) : 
 153     ItemImpl((SecItemClass
) (key
->keyClass() + CSSM_DL_DB_RECORD_PUBLIC_KEY
), (OSType
)0, (UInt32
)0, (const void*)NULL
), 
 156         mPubKeyHash(Allocator::standard()) 
 158         if (key
->keyClass() > CSSM_KEYCLASS_SESSION_KEY
) 
 159                 MacOSError::throwMe(errSecParam
); 
 169     //Create a new CSPDLTransaction 
 170     Db 
db(mKeychain
->database()); 
 171     CSPDLTransaction 
transaction(db
); 
 175     /* Update integrity on key */ 
 178     transaction
.commit(); 
 182 KeyItem::copyTo(const Keychain 
&keychain
, Access 
*newAccess
) 
 184         if (!(keychain
->database()->dl()->subserviceMask() & CSSM_SERVICE_CSP
)) 
 185                 MacOSError::throwMe(errSecInvalidKeychain
); 
 187         /* Get the destination keychain's db. */ 
 188         SSDbImpl
* dbImpl 
= dynamic_cast<SSDbImpl
*>(&(*keychain
->database())); 
 191                 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
); 
 196         /* Make sure mKey is valid. */ 
 197         const CSSM_KEY 
*cssmKey 
= key(); 
 198         if (cssmKey 
&& (0==(cssmKey
->KeyHeader
.KeyAttr 
& CSSM_KEYATTR_EXTRACTABLE
))) 
 200                 MacOSError::throwMe(errSecDataNotAvailable
); 
 203         // Generate a random label to use initially 
 204         CssmClient::CSP 
appleCsp(gGuidAppleCSP
); 
 205         CssmClient::Random 
random(appleCsp
, CSSM_ALGID_APPLE_YARROW
); 
 206         uint8 labelBytes
[20]; 
 207         CssmData 
label(labelBytes
, sizeof(labelBytes
)); 
 208         random
.generate(label
, (uint32
)label
.Length
); 
 210         /* Set up the ACL for the new key. */ 
 211         SecPointer
<Access
> access
; 
 215                 access 
= new Access(*mKey
); 
 217         /* Generate a random 3DES wrapping Key. */ 
 218         CssmClient::GenerateKey 
genKey(csp(), CSSM_ALGID_3DES_3KEY
, 192); 
 219         CssmClient::Key 
wrappingKey(genKey(KeySpec(CSSM_KEYUSE_WRAP 
| CSSM_KEYUSE_UNWRAP
, 
 220                 CSSM_KEYATTR_EXTRACTABLE 
/* | CSSM_KEYATTR_RETURN_DATA */))); 
 222         /* make a random IV */ 
 224         CssmData 
iv(ivBytes
, sizeof(ivBytes
)); 
 225         random
.generate(iv
, (uint32
)iv
.length()); 
 227         /* Extract the key by wrapping it with the wrapping key. */ 
 228         CssmClient::WrapKey 
wrap(csp(), CSSM_ALGID_3DES_3KEY_EDE
); 
 229         wrap
.key(wrappingKey
); 
 230         wrap
.cred(getCredentials(CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED
, kSecCredentialTypeDefault
)); 
 231         wrap
.mode(CSSM_ALGMODE_ECBPad
); 
 232         wrap
.padding(CSSM_PADDING_PKCS7
); 
 234         CssmClient::Key 
wrappedKey(wrap(mKey
)); 
 236         /* Unwrap the new key into the new Keychain. */ 
 237         CssmClient::UnwrapKey 
unwrap(keychain
->csp(), CSSM_ALGID_3DES_3KEY_EDE
); 
 238         unwrap
.key(wrappingKey
); 
 239         unwrap
.mode(CSSM_ALGMODE_ECBPad
); 
 240         unwrap
.padding(CSSM_PADDING_PKCS7
); 
 241         unwrap
.initVector(iv
); 
 243         /* Setup the dldbHandle in the context. */ 
 244         unwrap
.add(CSSM_ATTRIBUTE_DL_DB_HANDLE
, ssDb
->handle()); 
 246         /* Set up an initial aclEntry so we can change it after the unwrap. */ 
 247         Access::Maker 
maker(Allocator::standard(), Access::Maker::kAnyMakerType
); 
 248         ResourceControlContext rcc
; 
 249         maker
.initialOwner(rcc
, NULL
); 
 250         unwrap
.owner(rcc
.input()); 
 252         /* Unwrap the key. */ 
 253         uint32 usage 
= mKey
->usage(); 
 254         /* Work around csp brokeness where it sets all usage bits in the Keyheader when CSSM_KEYUSE_ANY is set. */ 
 255         if (usage 
& CSSM_KEYUSE_ANY
) 
 256                 usage 
= CSSM_KEYUSE_ANY
; 
 258         CssmClient::Key 
unwrappedKey(unwrap(wrappedKey
, KeySpec(usage
, 
 259                 (mKey
->attributes() | CSSM_KEYATTR_PERMANENT
) & ~(CSSM_KEYATTR_ALWAYS_SENSITIVE 
| CSSM_KEYATTR_NEVER_EXTRACTABLE
), 
 262         /* Look up unwrapped key in the DLDB. */ 
 263         DbUniqueRecord uniqueId
; 
 264         SSDbCursor 
dbCursor(ssDb
, 1); 
 265         dbCursor
->recordType(recordType()); 
 266         dbCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, label
); 
 267         CssmClient::Key copiedKey
; 
 268         if (!dbCursor
->nextKey(NULL
, copiedKey
, uniqueId
)) 
 269                 MacOSError::throwMe(errSecItemNotFound
); 
 271         /* Copy the Label, PrintName and ApplicationTag attributes from the old key to the new one. */ 
 273         DbAttributes 
oldDbAttributes(mUniqueId
->database(), 3); 
 274         oldDbAttributes
.add(kInfoKeyLabel
); 
 275         oldDbAttributes
.add(kInfoKeyPrintName
); 
 276         oldDbAttributes
.add(kInfoKeyApplicationTag
); 
 277         mUniqueId
->get(&oldDbAttributes
, NULL
); 
 280                 uniqueId
->modify(recordType(), &oldDbAttributes
, NULL
, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
); 
 284                 // clean up after trying to insert a duplicate key 
 285                 uniqueId
->deleteRecord (); 
 289     /* Set the acl and owner on the unwrapped key. See note in ItemImpl::copyTo about removing rights. */ 
 290     access
->removeAclsForRight(CSSM_ACL_AUTHORIZATION_PARTITION_ID
); 
 291     access
->removeAclsForRight(CSSM_ACL_AUTHORIZATION_INTEGRITY
); 
 292         access
->setAccess(*unwrappedKey
, maker
); 
 294         /* Return a keychain item which represents the new key.  */ 
 295         Item 
item(keychain
->item(recordType(), uniqueId
)); 
 297     KCEventNotifier::PostKeychainEvent(kSecAddEvent
, keychain
, item
); 
 303 KeyItem::importTo(const Keychain 
&keychain
, Access 
*newAccess
, SecKeychainAttributeList 
*attrList
) 
 305         if (!(keychain
->database()->dl()->subserviceMask() & CSSM_SERVICE_CSP
)) 
 306                 MacOSError::throwMe(errSecInvalidKeychain
); 
 308         /* Get the destination keychain's db. */ 
 309         SSDbImpl
* dbImpl 
= dynamic_cast<SSDbImpl
*>(&(*keychain
->database())); 
 311                 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
); 
 315         /* Make sure mKey is valid. */ 
 316         /* We can't call key() here, since we won't have a unique record id yet */ 
 318                 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
); 
 320         // Generate a random label to use initially 
 321         CssmClient::CSP 
appleCsp(gGuidAppleCSP
); 
 322         CssmClient::Random 
random(appleCsp
, CSSM_ALGID_APPLE_YARROW
); 
 323         uint8 labelBytes
[20]; 
 324         CssmData 
label(labelBytes
, sizeof(labelBytes
)); 
 325         random
.generate(label
, (uint32
)label
.Length
); 
 327         /* Set up the ACL for the new key. */ 
 328         SecPointer
<Access
> access
; 
 332                 access 
= new Access(*mKey
); 
 334         /* Generate a random 3DES wrapping Key. */ 
 335         CssmClient::GenerateKey 
genKey(csp(), CSSM_ALGID_3DES_3KEY
, 192); 
 336         CssmClient::Key 
wrappingKey(genKey(KeySpec(CSSM_KEYUSE_WRAP 
| CSSM_KEYUSE_UNWRAP
, 
 337                 CSSM_KEYATTR_EXTRACTABLE 
/* | CSSM_KEYATTR_RETURN_DATA */))); 
 339         /* make a random IV */ 
 341         CssmData 
iv(ivBytes
, sizeof(ivBytes
)); 
 342         random
.generate(iv
, (uint32
)iv
.length()); 
 344         /* Extract the key by wrapping it with the wrapping key. */ 
 345         CssmClient::WrapKey 
wrap(csp(), CSSM_ALGID_3DES_3KEY_EDE
); 
 346         wrap
.key(wrappingKey
); 
 347         wrap
.cred(getCredentials(CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED
, kSecCredentialTypeDefault
)); 
 348         wrap
.mode(CSSM_ALGMODE_ECBPad
); 
 349         wrap
.padding(CSSM_PADDING_PKCS7
); 
 351         CssmClient::Key 
wrappedKey(wrap(mKey
)); 
 353         /* Unwrap the new key into the new Keychain. */ 
 354         CssmClient::UnwrapKey 
unwrap(keychain
->csp(), CSSM_ALGID_3DES_3KEY_EDE
); 
 355     if (csp()->guid() != keychain
->csp()->guid()) { 
 356         // Prepare wrapping key to be usable in target keychain's CSP. 
 357         CssmClient::WrapKey 
exportWrapKey(csp(), CSSM_ALGID_NONE
); 
 358         CssmClient::Key 
exportedWrappingKey(exportWrapKey(wrappingKey
)); 
 359         CssmClient::UnwrapKey 
importUnwrapKey(keychain
->csp(), CSSM_ALGID_NONE
); 
 360         CssmClient::Key 
importedWrappingKey(importUnwrapKey(exportedWrappingKey
, KeySpec(CSSM_KEYUSE_UNWRAP
, 0))); 
 361         unwrap
.key(importedWrappingKey
); 
 363         // Wrapping key can be used directly, because source and target CSPs are the same. 
 364         unwrap
.key(wrappingKey
); 
 366         unwrap
.mode(CSSM_ALGMODE_ECBPad
); 
 367         unwrap
.padding(CSSM_PADDING_PKCS7
); 
 368         unwrap
.initVector(iv
); 
 370         /* Setup the dldbHandle in the context. */ 
 371         unwrap
.add(CSSM_ATTRIBUTE_DL_DB_HANDLE
, ssDb
->handle()); 
 373         /* Set up an initial aclEntry so we can change it after the unwrap. */ 
 374         Access::Maker 
maker(Allocator::standard(), Access::Maker::kAnyMakerType
); 
 375         ResourceControlContext rcc
; 
 376         maker
.initialOwner(rcc
, NULL
); 
 377         unwrap
.owner(rcc
.input()); 
 379         /* Unwrap the key. */ 
 380         uint32 usage 
= mKey
->usage(); 
 381         /* Work around csp brokeness where it sets all usage bits in the Keyheader when CSSM_KEYUSE_ANY is set. */ 
 382         if (usage 
& CSSM_KEYUSE_ANY
) 
 383                 usage 
= CSSM_KEYUSE_ANY
; 
 385         CssmClient::Key 
unwrappedKey(unwrap(wrappedKey
, KeySpec(usage
, 
 386                 (mKey
->attributes() | CSSM_KEYATTR_PERMANENT
) & ~(CSSM_KEYATTR_ALWAYS_SENSITIVE 
| CSSM_KEYATTR_NEVER_EXTRACTABLE
), 
 389         /* Look up unwrapped key in the DLDB. */ 
 390         DbUniqueRecord uniqueId
; 
 391         SSDbCursor 
dbCursor(ssDb
, 1); 
 392         dbCursor
->recordType(recordType()); 
 393         dbCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, label
); 
 394         CssmClient::Key copiedKey
; 
 395         if (!dbCursor
->nextKey(NULL
, copiedKey
, uniqueId
)) 
 396                 MacOSError::throwMe(errSecItemNotFound
); 
 398         // Set the initial label, application label, and application tag (if provided) 
 400                 DbAttributes newDbAttributes
; 
 402                 for (UInt32 index
=0; index 
< attrList
->count
; index
++) { 
 403                         SecKeychainAttribute attr 
= attrList
->attr
[index
]; 
 404                         CssmData 
attrData(attr
.data
, attr
.length
); 
 405                         if (attr
.tag 
== kSecKeyPrintName
) { 
 406                                 newDbAttributes
.add(kInfoKeyPrintName
, attrData
); 
 408                         if (attr
.tag 
== kSecKeyLabel
) { 
 409                                 newDbAttributes
.add(kInfoKeyLabel
, attrData
); 
 411                         if (attr
.tag 
== kSecKeyApplicationTag
) { 
 412                                 newDbAttributes
.add(kInfoKeyApplicationTag
, attrData
); 
 416         modifyUniqueId(keychain
, ssDb
, uniqueId
, newDbAttributes
, recordType()); 
 419         /* Set the acl and owner on the unwrapped key. */ 
 420     addIntegrity(*access
); 
 421         access
->setAccess(*unwrappedKey
, maker
); 
 423         /* Return a keychain item which represents the new key.  */ 
 424         Item 
item(keychain
->item(recordType(), uniqueId
)); 
 426     KCEventNotifier::PostKeychainEvent(kSecAddEvent
, keychain
, item
); 
 437 KeyItem::add(Keychain 
&keychain
) 
 439         MacOSError::throwMe(errSecUnimplemented
); 
 442 CssmClient::SSDbUniqueRecord
 
 443 KeyItem::ssDbUniqueRecord() 
 445         DbUniqueRecordImpl 
*impl 
= &*dbUniqueRecord(); 
 446         Security::CssmClient::SSDbUniqueRecordImpl 
*simpl 
= dynamic_cast<Security::CssmClient::SSDbUniqueRecordImpl 
*>(impl
); 
 449                 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
); 
 452         return CssmClient::SSDbUniqueRecord(simpl
); 
 456 KeyItem::unverifiedKeyHeader() { 
 457     return unverifiedKey()->header(); 
 461 KeyItem::unverifiedKey() 
 463         StLock
<Mutex
>_(mMutex
); 
 466                 CssmClient::SSDbUniqueRecord 
uniqueId(ssDbUniqueRecord()); 
 467                 CssmDataContainer 
dataBlob(uniqueId
->allocator()); 
 468                 uniqueId
->get(NULL
, &dataBlob
); 
 469                 return CssmClient::Key(uniqueId
->database()->csp(), *reinterpret_cast<CssmKey 
*>(dataBlob
.Data
)); 
 478     StLock
<Mutex
>_(mMutex
); 
 481         mKey 
= unverifiedKey(); 
 484             if(!ItemImpl::checkIntegrity(*mKey
)) { 
 485                 secnotice("integrity", "key has no integrity, denying access"); 
 487                 CssmError::throwMe(errSecInvalidItemRef
); 
 489         } catch(CssmError cssme
) { 
 491             secnotice("integrity", "error while checking integrity, denying access: %s", cssme
.what()); 
 506 const CSSM_X509_ALGORITHM_IDENTIFIER
& 
 507 KeyItem::algorithmIdentifier() 
 511         CSSM_KEY_TYPE algorithm
 
 512                 CSSM_KEY_PTR cssmKey 
=  (CSSM_KEY_PTR
)thisData
->Data
; 
 514         static void printKeyHeader( 
 515         const CSSM_KEYHEADER 
&hdr
) 
 517         printf("   Algorithm       : "); 
 518         switch(hdr
.AlgorithmId
) { 
 519 CSSM_X509_ALGORITHM_IDENTIFIER algID
; 
 521 CSSM_OID 
*CL_algToOid( 
 522         CSSM_ALGORITHMS algId
) 
 523 typedef struct cssm_x509_algorithm_identifier 
{ 
 525     CSSM_DATA parameters
; 
 526 } CSSM_X509_ALGORITHM_IDENTIFIER
, *CSSM_X509_ALGORITHM_IDENTIFIER_PTR
; 
 533  * itemID, used to locate Extended Attributes, is the public key hash for keys. 
 535 const CssmData 
&KeyItem::itemID() 
 537         if(mPubKeyHash
.length() == 0) { 
 539                  * Fetch the attribute from disk. 
 541                 UInt32 tag 
= kSecKeyLabel
; 
 543                 SecKeychainAttributeInfo attrInfo 
= {1, &tag
, &format
}; 
 544                 SecKeychainAttributeList 
*attrList 
= NULL
; 
 545                 getAttributesAndData(&attrInfo
, NULL
, &attrList
, NULL
, NULL
); 
 546                 if((attrList 
== NULL
) || (attrList
->count 
!= 1)) { 
 547                         MacOSError::throwMe(errSecNoSuchAttr
); 
 549                 mPubKeyHash
.copy(attrList
->attr
->data
, attrList
->attr
->length
); 
 550                 freeAttributesAndData(attrList
, NULL
); 
 557 KeyItem::strengthInBits(const CSSM_X509_ALGORITHM_IDENTIFIER 
*algid
) 
 559         // @@@ Make a context with key based on algid and use that to get the effective keysize and not just the logical one. 
 560         CSSM_KEY_SIZE keySize 
= {}; 
 561         CSSM_RETURN rv 
= CSSM_QueryKeySizeInBits (csp()->handle(), 
 568         return keySize
.LogicalKeySizeInBits
; 
 571 const AccessCredentials 
* 
 572 KeyItem::getCredentials( 
 573         CSSM_ACL_AUTHORIZATION_TAG operation
, 
 574         SecCredentialType credentialType
) 
 576         // @@@ Fix this to actually examine the ACL for this key and consider operation and do the right thing. 
 577         //AutoAclEntryInfoList aclInfos; 
 578         //key()->getAcl(aclInfos); 
 580         bool smartcard 
= keychain() != NULL 
? (keychain()->database()->dl()->guid() == gGuidAppleSdCSPDL
) : false; 
 583         switch (credentialType
) 
 585         case kSecCredentialTypeDefault
: 
 586                 return smartcard
?globals().smartcardItemCredentials():globals().itemCredentials(); 
 587         case kSecCredentialTypeWithUI
: 
 588                 return smartcard
?globals().smartcardItemCredentials():factory
.promptCred(); 
 589         case kSecCredentialTypeNoUI
: 
 590                 return factory
.nullCred(); 
 592                 MacOSError::throwMe(errSecParam
); 
 597 KeyItem::publicKey() { 
 602 KeyItem::operator == (KeyItem 
&other
) 
 607                 return this == &other
; 
 610         // If keychains are different, then keys are different 
 611         Keychain otherKeychain 
= other
.keychain(); 
 612         return (mKeychain 
&& otherKeychain 
&& (*mKeychain 
== *otherKeychain
)); 
 618         CSSM_ALGORITHMS algorithm
, 
 619         uint32 keySizeInBits
, 
 620         CSSM_CC_HANDLE contextHandle
, 
 621         CSSM_KEYUSE publicKeyUsage
, 
 622         uint32 publicKeyAttr
, 
 623         CSSM_KEYUSE privateKeyUsage
, 
 624         uint32 privateKeyAttr
, 
 625         SecPointer
<Access
> initialAccess
, 
 626         SecPointer
<KeyItem
> &outPublicKey
, 
 627         SecPointer
<KeyItem
> &outPrivateKey
) 
 631     const AccessCredentials 
*cred 
= NULL
; 
 632     CssmClient::CSP 
appleCsp(gGuidAppleCSP
); 
 633     CssmClient::CSP csp 
= appleCsp
; 
 634     ResourceControlContext rcc
; 
 635     memset(&rcc
, 0, sizeof(rcc
)); 
 637     uint8 labelBytes
[20]; 
 640         if (!(keychain
->database()->dl()->subserviceMask() & CSSM_SERVICE_CSP
)) 
 641             MacOSError::throwMe(errSecInvalidKeychain
); 
 643         SSDbImpl
* impl 
= dynamic_cast<SSDbImpl
*>(&(*keychain
->database())); 
 645             CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
); 
 648         csp 
= keychain
->csp(); 
 650         // Generate a random label to use initially 
 651         CssmClient::Random 
random(appleCsp
, CSSM_ALGID_APPLE_YARROW
); 
 652         label 
= CssmData(labelBytes
, sizeof(labelBytes
)); 
 653         random
.generate(label
, (uint32
)label
.length()); 
 655         // Create a Access::Maker for the initial owner of the private key. 
 656         // @@@ Potentially provide a credential argument which allows us to generate keys in the csp.  Currently the CSP let's anyone do this, but we might restrict this in the future, f.e. a smartcard could require out of band pin entry before a key can be generated. 
 657         maker
.initialOwner(rcc
); 
 658         // Create the cred we need to manipulate the keys until we actually set a new access control for them. 
 662     CssmKey publicCssmKey
, privateCssmKey
; 
 663         CSSM_CC_HANDLE ccHandle 
= 0; 
 665     bool freePublicKey 
= false; 
 666     bool freePrivateKey 
= false; 
 667     bool deleteContext 
= false; 
 668     bool permanentPubKey 
= false; 
 669     bool permanentPrivKey 
= false; 
 671         SecPointer
<KeyItem
> publicKeyItem
, privateKeyItem
; 
 675             ccHandle 
= contextHandle
; 
 677                         status 
= CSSM_CSP_CreateKeyGenContext(csp
->handle(), algorithm
, keySizeInBits
, NULL
, NULL
, NULL
, NULL
, NULL
, &ccHandle
); 
 679                                 CssmError::throwMe(status
); 
 680                         deleteContext 
= true; 
 684             CSSM_DL_DB_HANDLE dldbHandle 
= ssDb
->handle(); 
 685             CSSM_DL_DB_HANDLE_PTR dldbHandlePtr 
= &dldbHandle
; 
 686             CSSM_CONTEXT_ATTRIBUTE contextAttributes 
= { CSSM_ATTRIBUTE_DL_DB_HANDLE
, sizeof(dldbHandle
), { (char *)dldbHandlePtr 
} }; 
 687             status 
= CSSM_UpdateContextAttributes(ccHandle
, 1, &contextAttributes
); 
 689                 CssmError::throwMe(status
); 
 692                 // Generate the keypair 
 693                 status 
= CSSM_GenerateKeyPair(ccHandle
, publicKeyUsage
, publicKeyAttr
, &label
, &publicCssmKey
, privateKeyUsage
, privateKeyAttr
, &label
, &rcc
, &privateCssmKey
); 
 695                         CssmError::throwMe(status
); 
 696         if ((publicKeyAttr 
& CSSM_KEYATTR_PERMANENT
) != 0) { 
 697             permanentPubKey 
= true; 
 698             freePublicKey 
= true; 
 700         if ((privateKeyAttr 
& CSSM_KEYATTR_PERMANENT
) != 0) { 
 701             permanentPrivKey 
= true; 
 702             freePrivateKey 
= true; 
 705                 // Find the keys if we just generated them in the DL so we can change the label to be the hash of the public key, and 
 706                 // fix up other attributes. 
 708                 // Look up public key in the DLDB. 
 709         CssmClient::Key publicKey
; 
 710         DbAttributes pubDbAttributes
; 
 711         DbUniqueRecord pubUniqueId
; 
 712         if (permanentPubKey 
&& ssDb
) { 
 713             SSDbCursor 
dbPubCursor(ssDb
, 1); 
 714             dbPubCursor
->recordType(CSSM_DL_DB_RECORD_PUBLIC_KEY
); 
 715             dbPubCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, label
); 
 716             if (!dbPubCursor
->nextKey(&pubDbAttributes
, publicKey
, pubUniqueId
)) 
 717                 MacOSError::throwMe(errSecItemNotFound
); 
 719             publicKey 
= CssmClient::Key(csp
, publicCssmKey
); 
 720             outPublicKey 
= new KeyItem(publicKey
); 
 721             freePublicKey 
= false; 
 724                 // Look up private key in the DLDB. 
 725         CssmClient::Key privateKey
; 
 726         DbAttributes privDbAttributes
; 
 727         DbUniqueRecord privUniqueId
; 
 728         if (permanentPrivKey 
&& ssDb
) { 
 729             SSDbCursor 
dbPrivCursor(ssDb
, 1); 
 730             dbPrivCursor
->recordType(CSSM_DL_DB_RECORD_PRIVATE_KEY
); 
 731             dbPrivCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, label
); 
 732             if (!dbPrivCursor
->nextKey(&privDbAttributes
, privateKey
, privUniqueId
)) 
 733                 MacOSError::throwMe(errSecItemNotFound
); 
 735             privateKey 
= CssmClient::Key(csp
, privateCssmKey
); 
 736             outPrivateKey 
= new KeyItem(privateKey
); 
 737             freePrivateKey 
= false; 
 741             // Convert reference public key to a raw key so we can use it in the appleCsp. 
 742             CssmClient::WrapKey 
wrap(csp
, CSSM_ALGID_NONE
); 
 744             CssmClient::Key rawPubKey 
= wrap(publicKey
); 
 746             // Calculate the hash of the public key using the appleCSP. 
 747             CssmClient::PassThrough 
passThrough(appleCsp
); 
 749             /* Given a CSSM_KEY_PTR in any format, obtain the SHA-1 hash of the 
 750              * associated key blob. 
 751              * Key is specified in CSSM_CSP_CreatePassThroughContext. 
 752              * Hash is allocated by the CSP, in the App's memory, and returned 
 754             passThrough
.key(rawPubKey
); 
 755             CssmData 
*pubKeyHashData
; 
 756             passThrough(CSSM_APPLECSP_KEYDIGEST
, (const void *)NULL
, &pubKeyHashData
); 
 757             CssmAutoData 
pubKeyHash(passThrough
.allocator()); 
 758             pubKeyHash
.set(*pubKeyHashData
); 
 759             passThrough
.allocator().free(pubKeyHashData
); 
 761             auto_ptr
<string
> privDescription
; 
 762             auto_ptr
<string
> pubDescription
; 
 764                 privDescription
.reset(new string(initialAccess
->promptDescription())); 
 765                 pubDescription
.reset(new string(initialAccess
->promptDescription())); 
 768                 /* this path taken if no promptDescription available, e.g., for complex ACLs */ 
 769                 privDescription
.reset(new string("Private key")); 
 770                 pubDescription
.reset(new string("Public key")); 
 773             if (permanentPubKey
) { 
 774                 // Set the label of the public key to the public key hash. 
 775                 // Set the PrintName of the public key to the description in the acl. 
 776                 pubDbAttributes
.add(kInfoKeyLabel
, pubKeyHash
.get()); 
 777                 pubDbAttributes
.add(kInfoKeyPrintName
, *pubDescription
); 
 778                 modifyUniqueId(keychain
, ssDb
, pubUniqueId
, pubDbAttributes
, CSSM_DL_DB_RECORD_PUBLIC_KEY
); 
 780                 // Create keychain item which will represent the public key. 
 781                 publicKeyItem 
= dynamic_cast<KeyItem
*>(keychain
->item(CSSM_DL_DB_RECORD_PUBLIC_KEY
, pubUniqueId
).get()); 
 782                 if (!publicKeyItem
) { 
 783                     CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
); 
 786                 if (publicKeyAttr 
& CSSM_KEYATTR_PUBLIC_KEY_ENCRYPT
) { 
 788                      * Make the public key acl completely open. 
 789                      * If the key was not encrypted, it already has a wide-open 
 790                      * ACL (though that is a feature of securityd; it's not 
 791                      * CDSA-specified behavior). 
 793                     SecPointer
<Access
> pubKeyAccess(new Access()); 
 794                     publicKeyItem
->addIntegrity(*pubKeyAccess
); 
 795                     pubKeyAccess
->setAccess(*publicKey
, maker
); 
 797                 outPublicKey 
= publicKeyItem
; 
 800             if (permanentPrivKey
) { 
 801                 // Set the label of the private key to the public key hash. 
 802                 // Set the PrintName of the private key to the description in the acl. 
 803                 privDbAttributes
.add(kInfoKeyLabel
, pubKeyHash
.get()); 
 804                 privDbAttributes
.add(kInfoKeyPrintName
, *privDescription
); 
 805                 modifyUniqueId(keychain
, ssDb
, privUniqueId
, privDbAttributes
, CSSM_DL_DB_RECORD_PRIVATE_KEY
); 
 807                 // Create keychain item which will represent the private key. 
 808                 privateKeyItem 
= dynamic_cast<KeyItem
*>(keychain
->item(CSSM_DL_DB_RECORD_PRIVATE_KEY
, privUniqueId
).get()); 
 809                 if (!privateKeyItem
) { 
 810                     CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
); 
 813                 // Finally fix the acl and owner of the private key to the specified access control settings. 
 814                 privateKeyItem
->addIntegrity(*initialAccess
); 
 815                 initialAccess
->setAccess(*privateKey
, maker
); 
 816                 outPrivateKey 
= privateKeyItem
; 
 819         outPrivateKey
->mPublicKey 
= publicKey
; 
 823         // Delete the keys if something goes wrong so we don't end up with inaccessible keys in the database. 
 825                         CSSM_FreeKey(csp
->handle(), cred
, &publicCssmKey
, permanentPubKey
); 
 827         if (freePrivateKey
) { 
 828                         CSSM_FreeKey(csp
->handle(), cred
, &privateCssmKey
, permanentPrivKey
); 
 832                         CSSM_DeleteContext(ccHandle
); 
 838                 CSSM_FreeKey(csp
->handle(), NULL
, &publicCssmKey
, FALSE
); 
 840     if (freePrivateKey
) { 
 841                 CSSM_FreeKey(csp
->handle(), NULL
, &privateCssmKey
, FALSE
); 
 845                 CSSM_DeleteContext(ccHandle
); 
 848         if (permanentPubKey
) { 
 849             keychain
->postEvent(kSecAddEvent
, publicKeyItem
); 
 851         if (permanentPrivKey
) { 
 852             keychain
->postEvent(kSecAddEvent
, privateKeyItem
); 
 860         const CSSM_KEY 
&publicWrappedKey
, 
 861         const CSSM_KEY 
&privateWrappedKey
, 
 862         SecPointer
<Access
> initialAccess
, 
 863         SecPointer
<KeyItem
> &outPublicKey
, 
 864         SecPointer
<KeyItem
> &outPrivateKey
) 
 866         bool freePublicKey 
= false; 
 867         bool freePrivateKey 
= false; 
 868         bool deleteContext 
= false; 
 870         if (!(keychain
->database()->dl()->subserviceMask() & CSSM_SERVICE_CSP
)) 
 871                 MacOSError::throwMe(errSecInvalidKeychain
); 
 873         SSDbImpl
* impl 
= dynamic_cast<SSDbImpl 
*>(&(*keychain
->database())); 
 876                 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
); 
 880         CssmClient::CSP 
csp(keychain
->csp()); 
 881         CssmClient::CSP 
appleCsp(gGuidAppleCSP
); 
 883         // Create a Access::Maker for the initial owner of the private key. 
 884         ResourceControlContext rcc
; 
 885         memset(&rcc
, 0, sizeof(rcc
)); 
 886         Access::Maker 
maker(Allocator::standard(), Access::Maker::kAnyMakerType
); 
 887         // @@@ Potentially provide a credential argument which allows us to unwrap keys in the csp. 
 888         // Currently the CSP lets anyone do this, but we might restrict this in the future, e.g. 
 889         // a smartcard could require out of band pin entry before a key can be generated. 
 890         maker
.initialOwner(rcc
); 
 891         // Create the cred we need to manipulate the keys until we actually set a new access control for them. 
 892         const AccessCredentials 
*cred 
= maker
.cred(); 
 894         CSSM_KEY publicCssmKey
, privateCssmKey
; 
 895         memset(&publicCssmKey
, 0, sizeof(publicCssmKey
)); 
 896         memset(&privateCssmKey
, 0, sizeof(privateCssmKey
)); 
 898         CSSM_CC_HANDLE ccHandle 
= 0; 
 900         SecPointer
<KeyItem
> publicKeyItem
, privateKeyItem
; 
 905                 // Calculate the hash of the public key using the appleCSP. 
 906                 CssmClient::PassThrough 
passThrough(appleCsp
); 
 910                 /* Given a CSSM_KEY_PTR in any format, obtain the SHA-1 hash of the 
 911                 * associated key blob. 
 912                 * Key is specified in CSSM_CSP_CreatePassThroughContext. 
 913                 * Hash is allocated bythe CSP, in the App's memory, and returned 
 915                 passThrough
.key(&publicWrappedKey
); 
 916                 passThrough(CSSM_APPLECSP_KEYDIGEST
, NULL
, &outData
); 
 917                 cssmData 
= reinterpret_cast<CssmData 
*>(outData
); 
 918                 CssmData 
&pubKeyHash 
= *cssmData
; 
 920                 status 
= CSSM_CSP_CreateSymmetricContext(csp
->handle(), publicWrappedKey
.KeyHeader
.WrapAlgorithmId
, CSSM_ALGMODE_NONE
, NULL
, NULL
, NULL
, CSSM_PADDING_NONE
, NULL
, &ccHandle
); 
 922                         CssmError::throwMe(status
); 
 923                 deleteContext 
= true; 
 925                 CSSM_DL_DB_HANDLE dldbHandle 
= ssDb
->handle(); 
 926                 CSSM_DL_DB_HANDLE_PTR dldbHandlePtr 
= &dldbHandle
; 
 927                 CSSM_CONTEXT_ATTRIBUTE contextAttributes 
= { CSSM_ATTRIBUTE_DL_DB_HANDLE
, sizeof(dldbHandle
), { (char *)dldbHandlePtr 
} }; 
 928                 status 
= CSSM_UpdateContextAttributes(ccHandle
, 1, &contextAttributes
); 
 930                         CssmError::throwMe(status
); 
 932                 // Unwrap the the keys 
 933                 CSSM_DATA descriptiveData 
= {0, NULL
}; 
 935                 status 
= CSSM_UnwrapKey( 
 939                         publicWrappedKey
.KeyHeader
.KeyUsage
, 
 940                         publicWrappedKey
.KeyHeader
.KeyAttr 
| CSSM_KEYATTR_PERMANENT
, 
 947                         CssmError::throwMe(status
); 
 948                 freePublicKey 
= true; 
 950                 if (descriptiveData
.Data 
!= NULL
) 
 951                         free (descriptiveData
.Data
); 
 953                 status 
= CSSM_UnwrapKey( 
 957                         privateWrappedKey
.KeyHeader
.KeyUsage
, 
 958                         privateWrappedKey
.KeyHeader
.KeyAttr 
| CSSM_KEYATTR_PERMANENT
, 
 965                         CssmError::throwMe(status
); 
 967                 if (descriptiveData
.Data 
!= NULL
) 
 968                         free (descriptiveData
.Data
); 
 970                 freePrivateKey 
= true; 
 972                 // Find the keys we just generated in the DL to get SecKeyRefs to them 
 973                 // so we can change the label to be the hash of the public key, and 
 974                 // fix up other attributes. 
 976                 // Look up public key in the DLDB. 
 977                 DbAttributes pubDbAttributes
; 
 978                 DbUniqueRecord pubUniqueId
; 
 979                 SSDbCursor 
dbPubCursor(ssDb
, 1); 
 980                 dbPubCursor
->recordType(CSSM_DL_DB_RECORD_PUBLIC_KEY
); 
 981                 dbPubCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, pubKeyHash
); 
 982                 CssmClient::Key publicKey
; 
 983                 if (!dbPubCursor
->nextKey(&pubDbAttributes
, publicKey
, pubUniqueId
)) 
 984                         MacOSError::throwMe(errSecItemNotFound
); 
 986                 // Look up private key in the DLDB. 
 987                 DbAttributes privDbAttributes
; 
 988                 DbUniqueRecord privUniqueId
; 
 989                 SSDbCursor 
dbPrivCursor(ssDb
, 1); 
 990                 dbPrivCursor
->recordType(CSSM_DL_DB_RECORD_PRIVATE_KEY
); 
 991                 dbPrivCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, pubKeyHash
); 
 992                 CssmClient::Key privateKey
; 
 993                 if (!dbPrivCursor
->nextKey(&privDbAttributes
, privateKey
, privUniqueId
)) 
 994                         MacOSError::throwMe(errSecItemNotFound
); 
 996                 // @@@ Not exception safe! 
 997                 csp
.allocator().free(cssmData
->Data
); 
 998                 csp
.allocator().free(cssmData
); 
1000                 auto_ptr
<string
>privDescription
; 
1001                 auto_ptr
<string
>pubDescription
; 
1003                         privDescription
.reset(new string(initialAccess
->promptDescription())); 
1004                         pubDescription
.reset(new string(initialAccess
->promptDescription())); 
1007                         /* this path taken if no promptDescription available, e.g., for complex ACLs */ 
1008                         privDescription
.reset(new string("Private key")); 
1009                         pubDescription
.reset(new string("Public key")); 
1012                 // Set the label of the public key to the public key hash. 
1013                 // Set the PrintName of the public key to the description in the acl. 
1014                 pubDbAttributes
.add(kInfoKeyPrintName
, *pubDescription
); 
1015         modifyUniqueId(keychain
, ssDb
, pubUniqueId
, pubDbAttributes
, CSSM_DL_DB_RECORD_PUBLIC_KEY
); 
1017                 // Set the label of the private key to the public key hash. 
1018                 // Set the PrintName of the private key to the description in the acl. 
1019                 privDbAttributes
.add(kInfoKeyPrintName
, *privDescription
); 
1020         modifyUniqueId(keychain
, ssDb
, privUniqueId
, privDbAttributes
, CSSM_DL_DB_RECORD_PRIVATE_KEY
); 
1022         // Create keychain items which will represent the keys. 
1023         publicKeyItem 
= dynamic_cast<KeyItem
*>(keychain
->item(CSSM_DL_DB_RECORD_PUBLIC_KEY
, pubUniqueId
).get()); 
1024         privateKeyItem 
= dynamic_cast<KeyItem
*>(keychain
->item(CSSM_DL_DB_RECORD_PRIVATE_KEY
, privUniqueId
).get()); 
1026         if (!publicKeyItem 
|| !privateKeyItem
) 
1028             CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
); 
1031         // Finally fix the acl and owner of the private key to the specified access control settings. 
1032         privateKeyItem
->addIntegrity(*initialAccess
); 
1033                 initialAccess
->setAccess(*privateKey
, maker
); 
1035                 // Make the public key acl completely open 
1036                 SecPointer
<Access
> pubKeyAccess(new Access()); 
1037         publicKeyItem
->addIntegrity(*pubKeyAccess
); 
1038                 pubKeyAccess
->setAccess(*publicKey
, maker
); 
1040         outPublicKey 
= publicKeyItem
; 
1041         outPrivateKey 
= privateKeyItem
; 
1046                         CSSM_FreeKey(csp
->handle(), cred
, &publicCssmKey
, TRUE
); 
1048                         CSSM_FreeKey(csp
->handle(), cred
, &privateCssmKey
, TRUE
); 
1051                         CSSM_DeleteContext(ccHandle
); 
1057                 CSSM_FreeKey(csp
->handle(), cred
, &publicCssmKey
, FALSE
); 
1059                 CSSM_FreeKey(csp
->handle(), cred
, &privateCssmKey
, FALSE
); 
1062                 CSSM_DeleteContext(ccHandle
); 
1064         if (keychain 
&& publicKeyItem 
&& privateKeyItem
) 
1066                 KCEventNotifier::PostKeychainEvent(kSecAddEvent
, keychain
, Item(publicKeyItem
)); 
1067                 KCEventNotifier::PostKeychainEvent(kSecAddEvent
, keychain
, Item(privateKeyItem
)); 
1072 KeyItem::generateWithAttributes(const SecKeychainAttributeList 
*attrList
, 
1074         CSSM_ALGORITHMS algorithm
, 
1075         uint32 keySizeInBits
, 
1076         CSSM_CC_HANDLE contextHandle
, 
1077         CSSM_KEYUSE keyUsage
, 
1079         SecPointer
<Access
> initialAccess
) 
1081         CssmClient::CSP 
appleCsp(gGuidAppleCSP
); 
1082         CssmClient::CSP 
csp(NULL
); 
1084         uint8 labelBytes
[20]; 
1085         CssmData 
label(labelBytes
, sizeof(labelBytes
)); 
1086         bool freeKey 
= false; 
1087         bool deleteContext 
= false; 
1088         const CSSM_DATA 
*plabel 
= NULL
; 
1092                 if (!(keychain
->database()->dl()->subserviceMask() & CSSM_SERVICE_CSP
)) 
1093                         MacOSError::throwMe(errSecInvalidKeychain
); 
1095                 SSDbImpl
* impl 
= dynamic_cast<SSDbImpl 
*>(&(*keychain
->database())); 
1098                         CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
); 
1102                 csp 
= keychain
->csp(); 
1104                 // Generate a random label to use initially 
1105                 CssmClient::Random 
random(appleCsp
, CSSM_ALGID_APPLE_YARROW
); 
1106                 random
.generate(label
, (uint32
)label
.Length
); 
1111                 // Not a persistent key so create it in the regular csp 
1115         // Create a Access::Maker for the initial owner of the private key. 
1116         ResourceControlContext 
*prcc 
= NULL
, rcc
; 
1117         const AccessCredentials 
*cred 
= NULL
; 
1118         Access::Maker maker
; 
1124                 memset(&rcc
, 0, sizeof(rcc
)); 
1125                 // @@@ Potentially provide a credential argument which allows us to generate keys in the csp. 
1126                 // Currently the CSP lets anyone do this, but we might restrict this in the future, e.g. a smartcard 
1127                 // could require out-of-band pin entry before a key can be generated. 
1128                 maker
.initialOwner(rcc
); 
1129                 // Create the cred we need to manipulate the keys until we actually set a new access control for them. 
1130                 cred 
= maker
.cred(); 
1133         if (!initialAccess
) { 
1134             // We don't have an access, but we need to set integrity. Make an Access. 
1135             initialAccess 
= new Access(label
.toString()); 
1141         CSSM_CC_HANDLE ccHandle 
= 0; 
1143         SecPointer
<KeyItem
> keyItem
; 
1148                         ccHandle 
= contextHandle
; 
1151                         status 
= CSSM_CSP_CreateKeyGenContext(csp
->handle(), algorithm
, keySizeInBits
, NULL
, NULL
, NULL
, NULL
, NULL
, &ccHandle
); 
1153                                 CssmError::throwMe(status
); 
1154                         deleteContext 
= true; 
1159                         CSSM_DL_DB_HANDLE dldbHandle 
= ssDb
->handle(); 
1160                         CSSM_DL_DB_HANDLE_PTR dldbHandlePtr 
= &dldbHandle
; 
1161                         CSSM_CONTEXT_ATTRIBUTE contextAttributes 
= { CSSM_ATTRIBUTE_DL_DB_HANDLE
, sizeof(dldbHandle
), { (char *)dldbHandlePtr 
} }; 
1162                         status 
= CSSM_UpdateContextAttributes(ccHandle
, 1, &contextAttributes
); 
1164                                 CssmError::throwMe(status
); 
1166                         keyAttr 
|= CSSM_KEYATTR_PERMANENT
; 
1170                 status 
= CSSM_GenerateKey(ccHandle
, keyUsage
, keyAttr
, plabel
, prcc
, &cssmKey
); 
1172                         CssmError::throwMe(status
); 
1177                         // Find the key we just generated in the DL and get a SecKeyRef 
1178                         // so we can specify the label attribute(s) and initial ACL. 
1180                         // Look up key in the DLDB. 
1181                         DbAttributes dbAttributes
; 
1182                         DbUniqueRecord uniqueId
; 
1183                         SSDbCursor 
dbCursor(ssDb
, 1); 
1184                         dbCursor
->recordType(CSSM_DL_DB_RECORD_SYMMETRIC_KEY
); 
1185                         dbCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, label
); 
1186                         CssmClient::Key key
; 
1187                         if (!dbCursor
->nextKey(&dbAttributes
, key
, uniqueId
)) 
1188                                 MacOSError::throwMe(errSecItemNotFound
); 
1190                         // Set the initial label, application label, and application tag (if provided) 
1192                                 DbAttributes newDbAttributes
; 
1194                                 for (UInt32 index
=0; index 
< attrList
->count
; index
++) { 
1195                                         SecKeychainAttribute attr 
= attrList
->attr
[index
]; 
1196                                         CssmData 
attrData(attr
.data
, attr
.length
); 
1197                                         if (attr
.tag 
== kSecKeyPrintName
) { 
1198                                                 newDbAttributes
.add(kInfoKeyPrintName
, attrData
); 
1200                                         if (attr
.tag 
== kSecKeyLabel
) { 
1201                                                 newDbAttributes
.add(kInfoKeyLabel
, attrData
); 
1203                                         if (attr
.tag 
== kSecKeyApplicationTag
) { 
1204                                                 newDbAttributes
.add(kInfoKeyApplicationTag
, attrData
); 
1208                 modifyUniqueId(keychain
, ssDb
, uniqueId
, newDbAttributes
, CSSM_DL_DB_RECORD_SYMMETRIC_KEY
); 
1211             // Create keychain item which will represent the key. 
1212             keyItem 
= dynamic_cast<KeyItem 
*>(keychain
->item(CSSM_DL_DB_RECORD_SYMMETRIC_KEY
, uniqueId
).get()); 
1214             // Finally, fix the acl and owner of the key to the specified access control settings. 
1215             keyItem
->addIntegrity(*initialAccess
); 
1216             initialAccess
->setAccess(*key
, maker
); 
1220                         CssmClient::Key 
tempKey(csp
, cssmKey
); 
1221                         keyItem 
= new KeyItem(tempKey
); 
1228                         // Delete the key if something goes wrong so we don't end up with inaccessible keys in the database. 
1229                         CSSM_FreeKey(csp
->handle(), cred
, &cssmKey
, TRUE
); 
1233                         CSSM_DeleteContext(ccHandle
); 
1240                 CSSM_FreeKey(csp
->handle(), NULL
, &cssmKey
, FALSE
); 
1244                 CSSM_DeleteContext(ccHandle
); 
1246         if (keychain 
&& keyItem
) 
1247                 keychain
->postEvent(kSecAddEvent
, keyItem
); 
1249         KeyItem
* item 
= dynamic_cast<KeyItem
*>(&*keyItem
); 
1252                 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
); 
1259 KeyItem::generate(Keychain keychain
, 
1260         CSSM_ALGORITHMS algorithm
, 
1261         uint32 keySizeInBits
, 
1262         CSSM_CC_HANDLE contextHandle
, 
1263         CSSM_KEYUSE keyUsage
, 
1265         SecPointer
<Access
> initialAccess
) 
1267         return KeyItem::generateWithAttributes(NULL
, keychain
, 
1268                 algorithm
, keySizeInBits
, contextHandle
, 
1269                 keyUsage
, keyAttr
, initialAccess
); 
1273 CFHashCode 
KeyItem::hash() 
1275         CFHashCode result 
= 0; 
1276         const CSSM_KEY 
*cssmKey 
= key(); 
1277         if (NULL 
!= cssmKey
) 
1279                 unsigned char digest
[CC_SHA256_DIGEST_LENGTH
]; 
1281                 CFIndex size_of_data 
= sizeof(CSSM_KEYHEADER
) +  cssmKey
->KeyData
.Length
; 
1283                 CFMutableDataRef temp_cfdata 
= CFDataCreateMutable(kCFAllocatorDefault
, size_of_data
); 
1284                 if (NULL 
== temp_cfdata
) 
1289                 CFDataAppendBytes(temp_cfdata
, (const UInt8 
*)cssmKey
, sizeof(CSSM_KEYHEADER
)); 
1290                 CFDataAppendBytes(temp_cfdata
, cssmKey
->KeyData
.Data
, cssmKey
->KeyData
.Length
); 
1292                 if (size_of_data 
< 80) 
1294                         // If it is less than 80 bytes then CFData can be used 
1295                         result 
= CFHash(temp_cfdata
); 
1296                         CFRelease(temp_cfdata
); 
1298                 // CFData truncates its hash value to 80 bytes. ???? 
1299                 // In order to do the 'right thing' a SHA 256 hash will be used to 
1300                 // include all of the data 
1303                         memset(digest
, 0, CC_SHA256_DIGEST_LENGTH
); 
1305                         CC_SHA256((const void *)CFDataGetBytePtr(temp_cfdata
), (CC_LONG
)CFDataGetLength(temp_cfdata
), digest
); 
1307                         CFDataRef data_to_hash 
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, 
1308                                 (const UInt8 
*)digest
, CC_SHA256_DIGEST_LENGTH
, kCFAllocatorNull
); 
1309                         result 
= CFHash(data_to_hash
); 
1310                         CFRelease(data_to_hash
); 
1311                         CFRelease(temp_cfdata
); 
1317 void KeyItem::setIntegrity(bool force
) { 
1318     ItemImpl::setIntegrity(*unverifiedKey(), force
); 
1321 bool KeyItem::checkIntegrity() { 
1322     if(!isPersistent()) { 
1327         // key() checks integrity of itself, and throws if there's a problem. 
1330     } catch (CssmError cssme
) { 
1335  void KeyItem::removeIntegrity(const AccessCredentials 
*cred
) { 
1336     ItemImpl::removeIntegrity(*key(), cred
); 
1339 // KeyItems are a little bit special: the only modifications you can do to them 
1340 // is to change their Print Name, Label, or Application Tag. 
1342 // When we do this modification, we need to look ahead to see if there's an item 
1343 // that's already there. If there are, we're going to throw a errSecDuplicateItem. 
1345 // Unless that item doesn't pass the integrity check, in which case we delete it 
1346 // and continue with the add. 
1347 void KeyItem::modifyUniqueId(Keychain keychain
, SSDb ssDb
, DbUniqueRecord
& uniqueId
, DbAttributes
& newDbAttributes
, CSSM_DB_RECORDTYPE recordType
) { 
1348     SSDbCursor 
otherDbCursor(ssDb
, 1); 
1349     otherDbCursor
->recordType(recordType
); 
1351     bool checkForDuplicates 
= false; 
1352     // Set up the ssdb cursor 
1353     CssmDbAttributeData
* label 
= newDbAttributes
.findAttribute(kInfoKeyLabel
); 
1355         otherDbCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, label
->at(0)); 
1356         checkForDuplicates 
= true; 
1358     CssmDbAttributeData
* apptag 
= newDbAttributes
.findAttribute(kInfoKeyApplicationTag
); 
1360         otherDbCursor
->add(CSSM_DB_EQUAL
, kInfoKeyApplicationTag
, apptag
->at(0)); 
1361         checkForDuplicates 
= true; 
1364     // KeyItems only have integrity if the keychain supports it; otherwise, 
1365     // don't pre-check for duplicates 
1366     if((!keychain
) || !keychain
->hasIntegrityProtection()) { 
1367         secnotice("integrity", "key skipping duplicate integrity check due to keychain version"); 
1368         checkForDuplicates 
= false; 
1371     if (checkForDuplicates
) { 
1372         secnotice("integrity", "looking for duplicates"); 
1373         // If there are duplicates that are invalid, delete it and 
1374         // continue. Otherwise, if there are duplicates, throw errSecDuplicateItem. 
1375         DbAttributes otherDbAttributes
; 
1376         DbUniqueRecord otherUniqueId
; 
1377         CssmClient::Key otherKey
; 
1379         while(otherDbCursor
->nextKey(&otherDbAttributes
, otherKey
, otherUniqueId
)) { 
1380             secnotice("integrity", "found a duplicate, checking integrity"); 
1382             PrimaryKey pk 
= keychain
->makePrimaryKey(recordType
, otherUniqueId
); 
1384             ItemImpl
* maybeItem 
= keychain
->_lookupItem(pk
); 
1386                 if(maybeItem
->checkIntegrity()) { 
1387                     secnotice("integrity", "duplicate is real, throwing error"); 
1388                     MacOSError::throwMe(errSecDuplicateItem
); 
1390                     secnotice("integrity", "existing duplicate item is invalid, removing..."); 
1391                     Item 
item(maybeItem
); 
1392                     keychain
->deleteItem(item
); 
1395                 KeyItem 
temp(keychain
, pk
, otherUniqueId
); 
1397                 if(temp
.checkIntegrity()) { 
1398                     secnotice("integrity", "duplicate is real, throwing error"); 
1399                     MacOSError::throwMe(errSecDuplicateItem
); 
1401                     secnotice("integrity", "duplicate is invalid, removing"); 
1402                     // Keychain's idea of deleting items involves notifications and callbacks. We don't want that, 
1403                     // (since this isn't a real item and it should go away quietly), so use this roundabout method. 
1404                     otherUniqueId
->deleteRecord(); 
1405                     keychain
->removeItem(temp
.primaryKey(), &temp
); 
1412         secinfo("integrity", "modifying unique id"); 
1413         uniqueId
->modify(recordType
, &newDbAttributes
, NULL
, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
); 
1414         secinfo("integrity", "done modifying unique id"); 
1415     } catch(CssmError e
) { 
1416         // Just in case something went wrong, clean up after this add 
1417         uniqueId
->deleteRecord();