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> 
  37 #include <security_keychain/Globals.h> 
  38 #include "KCEventNotifier.h" 
  39 #include <CommonCrypto/CommonDigest.h> 
  42 // @@@ This needs to be shared. 
  43 #pragma clang diagnostic push 
  44 #pragma clang diagnostic ignored "-Wunused-const-variable" 
  45 static CSSM_DB_NAME_ATTR(kInfoKeyPrintName
, kSecKeyPrintName
, (char*) "PrintName", 0, NULL
, BLOB
); 
  46 static CSSM_DB_NAME_ATTR(kInfoKeyLabel
, kSecKeyLabel
, (char*) "Label", 0, NULL
, BLOB
); 
  47 static CSSM_DB_NAME_ATTR(kInfoKeyApplicationTag
, kSecKeyApplicationTag
, (char*) "ApplicationTag", 0, NULL
, BLOB
); 
  48 #pragma clang diagnostic pop 
  50 using namespace KeychainCore
; 
  51 using namespace CssmClient
; 
  53 KeyItem::KeyItem(const Keychain 
&keychain
, const PrimaryKey 
&primaryKey
, const CssmClient::DbUniqueRecord 
&uniqueId
) : 
  54         ItemImpl(keychain
, primaryKey
, uniqueId
), 
  57         mPubKeyHash(Allocator::standard()) 
  61 KeyItem::KeyItem(const Keychain 
&keychain
, const PrimaryKey 
&primaryKey
)  : 
  62         ItemImpl(keychain
, primaryKey
), 
  65         mPubKeyHash(Allocator::standard()) 
  69 KeyItem
* KeyItem::make(const Keychain 
&keychain
, const PrimaryKey 
&primaryKey
, const CssmClient::DbUniqueRecord 
&uniqueId
) 
  71         KeyItem
* k 
= new KeyItem(keychain
, primaryKey
, uniqueId
); 
  72         keychain
->addItem(primaryKey
, k
); 
  78 KeyItem
* KeyItem::make(const Keychain 
&keychain
, const PrimaryKey 
&primaryKey
) 
  80         KeyItem
* k 
= new KeyItem(keychain
, primaryKey
); 
  81         keychain
->addItem(primaryKey
, k
); 
  87 KeyItem::KeyItem(KeyItem 
&keyItem
) : 
  91         mPubKeyHash(Allocator::standard()) 
  93         // @@@ this doesn't work for keys that are not in a keychain. 
  96 KeyItem::KeyItem(const CssmClient::Key 
&key
) : 
  97     ItemImpl(key
->keyClass() + CSSM_DL_DB_RECORD_PUBLIC_KEY
, (OSType
)0, (UInt32
)0, (const void*)NULL
), 
 100         mPubKeyHash(Allocator::standard()) 
 102         if (key
->keyClass() > CSSM_KEYCLASS_SESSION_KEY
) 
 103                 MacOSError::throwMe(errSecParam
); 
 117 KeyItem::copyTo(const Keychain 
&keychain
, Access 
*newAccess
) 
 119         if (!(keychain
->database()->dl()->subserviceMask() & CSSM_SERVICE_CSP
)) 
 120                 MacOSError::throwMe(errSecInvalidKeychain
); 
 122         /* Get the destination keychain's db. */ 
 123         SSDbImpl
* dbImpl 
= dynamic_cast<SSDbImpl
*>(&(*keychain
->database())); 
 126                 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
); 
 131         /* Make sure mKey is valid. */ 
 132         const CSSM_KEY 
*cssmKey 
= key(); 
 133         if (cssmKey 
&& (0==(cssmKey
->KeyHeader
.KeyAttr 
& CSSM_KEYATTR_EXTRACTABLE
))) 
 135                 MacOSError::throwMe(errSecDataNotAvailable
); 
 138         // Generate a random label to use initially 
 139         CssmClient::CSP 
appleCsp(gGuidAppleCSP
); 
 140         CssmClient::Random 
random(appleCsp
, CSSM_ALGID_APPLE_YARROW
); 
 141         uint8 labelBytes
[20]; 
 142         CssmData 
label(labelBytes
, sizeof(labelBytes
)); 
 143         random
.generate(label
, (uint32
)label
.Length
); 
 145         /* Set up the ACL for the new key. */ 
 146         SecPointer
<Access
> access
; 
 150                 access 
= new Access(*mKey
); 
 152         /* Generate a random 3DES wrapping Key. */ 
 153         CssmClient::GenerateKey 
genKey(csp(), CSSM_ALGID_3DES_3KEY
, 192); 
 154         CssmClient::Key 
wrappingKey(genKey(KeySpec(CSSM_KEYUSE_WRAP 
| CSSM_KEYUSE_UNWRAP
, 
 155                 CSSM_KEYATTR_EXTRACTABLE 
/* | CSSM_KEYATTR_RETURN_DATA */))); 
 157         /* make a random IV */ 
 159         CssmData 
iv(ivBytes
, sizeof(ivBytes
)); 
 160         random
.generate(iv
, (uint32
)iv
.length()); 
 162         /* Extract the key by wrapping it with the wrapping key. */ 
 163         CssmClient::WrapKey 
wrap(csp(), CSSM_ALGID_3DES_3KEY_EDE
); 
 164         wrap
.key(wrappingKey
); 
 165         wrap
.cred(getCredentials(CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED
, kSecCredentialTypeDefault
)); 
 166         wrap
.mode(CSSM_ALGMODE_ECBPad
); 
 167         wrap
.padding(CSSM_PADDING_PKCS7
); 
 169         CssmClient::Key 
wrappedKey(wrap(mKey
)); 
 171         /* Unwrap the new key into the new Keychain. */ 
 172         CssmClient::UnwrapKey 
unwrap(keychain
->csp(), CSSM_ALGID_3DES_3KEY_EDE
); 
 173         unwrap
.key(wrappingKey
); 
 174         unwrap
.mode(CSSM_ALGMODE_ECBPad
); 
 175         unwrap
.padding(CSSM_PADDING_PKCS7
); 
 176         unwrap
.initVector(iv
); 
 178         /* Setup the dldbHandle in the context. */ 
 179         unwrap
.add(CSSM_ATTRIBUTE_DL_DB_HANDLE
, ssDb
->handle()); 
 181         /* Set up an initial aclEntry so we can change it after the unwrap. */ 
 182         Access::Maker 
maker(Allocator::standard(), Access::Maker::kAnyMakerType
); 
 183         ResourceControlContext rcc
; 
 184         maker
.initialOwner(rcc
, NULL
); 
 185         unwrap
.owner(rcc
.input()); 
 187         /* Unwrap the key. */ 
 188         uint32 usage 
= mKey
->usage(); 
 189         /* Work around csp brokeness where it sets all usage bits in the Keyheader when CSSM_KEYUSE_ANY is set. */ 
 190         if (usage 
& CSSM_KEYUSE_ANY
) 
 191                 usage 
= CSSM_KEYUSE_ANY
; 
 193         CssmClient::Key 
unwrappedKey(unwrap(wrappedKey
, KeySpec(usage
, 
 194                 (mKey
->attributes() | CSSM_KEYATTR_PERMANENT
) & ~(CSSM_KEYATTR_ALWAYS_SENSITIVE 
| CSSM_KEYATTR_NEVER_EXTRACTABLE
), 
 197         /* Look up unwrapped key in the DLDB. */ 
 198         DbUniqueRecord uniqueId
; 
 199         SSDbCursor 
dbCursor(ssDb
, 1); 
 200         dbCursor
->recordType(recordType()); 
 201         dbCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, label
); 
 202         CssmClient::Key copiedKey
; 
 203         if (!dbCursor
->nextKey(NULL
, copiedKey
, uniqueId
)) 
 204                 MacOSError::throwMe(errSecItemNotFound
); 
 206         /* Copy the Label, PrintName and ApplicationTag attributes from the old key to the new one. */ 
 208         DbAttributes 
oldDbAttributes(mUniqueId
->database(), 3); 
 209         oldDbAttributes
.add(kInfoKeyLabel
); 
 210         oldDbAttributes
.add(kInfoKeyPrintName
); 
 211         oldDbAttributes
.add(kInfoKeyApplicationTag
); 
 212         mUniqueId
->get(&oldDbAttributes
, NULL
); 
 215                 uniqueId
->modify(recordType(), &oldDbAttributes
, NULL
, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
); 
 219                 // clean up after trying to insert a duplicate key 
 220                 uniqueId
->deleteRecord (); 
 224         /* Set the acl and owner on the unwrapped key. */ 
 225         access
->setAccess(*unwrappedKey
, maker
); 
 227         /* Return a keychain item which represents the new key.  */ 
 228         Item 
item(keychain
->item(recordType(), uniqueId
)); 
 230     KCEventNotifier::PostKeychainEvent(kSecAddEvent
, keychain
, item
); 
 236 KeyItem::importTo(const Keychain 
&keychain
, Access 
*newAccess
, SecKeychainAttributeList 
*attrList
) 
 238         if (!(keychain
->database()->dl()->subserviceMask() & CSSM_SERVICE_CSP
)) 
 239                 MacOSError::throwMe(errSecInvalidKeychain
); 
 241         /* Get the destination keychain's db. */ 
 242         SSDbImpl
* dbImpl 
= dynamic_cast<SSDbImpl
*>(&(*keychain
->database())); 
 244                 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
); 
 248         /* Make sure mKey is valid. */ 
 249         /* We can't call key() here, since we won't have a unique record id yet */ 
 251                 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
); 
 253         // Generate a random label to use initially 
 254         CssmClient::CSP 
appleCsp(gGuidAppleCSP
); 
 255         CssmClient::Random 
random(appleCsp
, CSSM_ALGID_APPLE_YARROW
); 
 256         uint8 labelBytes
[20]; 
 257         CssmData 
label(labelBytes
, sizeof(labelBytes
)); 
 258         random
.generate(label
, (uint32
)label
.Length
); 
 260         /* Set up the ACL for the new key. */ 
 261         SecPointer
<Access
> access
; 
 265                 access 
= new Access(*mKey
); 
 267         /* Generate a random 3DES wrapping Key. */ 
 268         CssmClient::GenerateKey 
genKey(csp(), CSSM_ALGID_3DES_3KEY
, 192); 
 269         CssmClient::Key 
wrappingKey(genKey(KeySpec(CSSM_KEYUSE_WRAP 
| CSSM_KEYUSE_UNWRAP
, 
 270                 CSSM_KEYATTR_EXTRACTABLE 
/* | CSSM_KEYATTR_RETURN_DATA */))); 
 272         /* make a random IV */ 
 274         CssmData 
iv(ivBytes
, sizeof(ivBytes
)); 
 275         random
.generate(iv
, (uint32
)iv
.length()); 
 277         /* Extract the key by wrapping it with the wrapping key. */ 
 278         CssmClient::WrapKey 
wrap(csp(), CSSM_ALGID_3DES_3KEY_EDE
); 
 279         wrap
.key(wrappingKey
); 
 280         wrap
.cred(getCredentials(CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED
, kSecCredentialTypeDefault
)); 
 281         wrap
.mode(CSSM_ALGMODE_ECBPad
); 
 282         wrap
.padding(CSSM_PADDING_PKCS7
); 
 284         CssmClient::Key 
wrappedKey(wrap(mKey
)); 
 286         /* Unwrap the new key into the new Keychain. */ 
 287         CssmClient::UnwrapKey 
unwrap(keychain
->csp(), CSSM_ALGID_3DES_3KEY_EDE
); 
 288         unwrap
.key(wrappingKey
); 
 289         unwrap
.mode(CSSM_ALGMODE_ECBPad
); 
 290         unwrap
.padding(CSSM_PADDING_PKCS7
); 
 291         unwrap
.initVector(iv
); 
 293         /* Setup the dldbHandle in the context. */ 
 294         unwrap
.add(CSSM_ATTRIBUTE_DL_DB_HANDLE
, ssDb
->handle()); 
 296         /* Set up an initial aclEntry so we can change it after the unwrap. */ 
 297         Access::Maker 
maker(Allocator::standard(), Access::Maker::kAnyMakerType
); 
 298         ResourceControlContext rcc
; 
 299         maker
.initialOwner(rcc
, NULL
); 
 300         unwrap
.owner(rcc
.input()); 
 302         /* Unwrap the key. */ 
 303         uint32 usage 
= mKey
->usage(); 
 304         /* Work around csp brokeness where it sets all usage bits in the Keyheader when CSSM_KEYUSE_ANY is set. */ 
 305         if (usage 
& CSSM_KEYUSE_ANY
) 
 306                 usage 
= CSSM_KEYUSE_ANY
; 
 308         CssmClient::Key 
unwrappedKey(unwrap(wrappedKey
, KeySpec(usage
, 
 309                 (mKey
->attributes() | CSSM_KEYATTR_PERMANENT
) & ~(CSSM_KEYATTR_ALWAYS_SENSITIVE 
| CSSM_KEYATTR_NEVER_EXTRACTABLE
), 
 312         /* Look up unwrapped key in the DLDB. */ 
 313         DbUniqueRecord uniqueId
; 
 314         SSDbCursor 
dbCursor(ssDb
, 1); 
 315         dbCursor
->recordType(recordType()); 
 316         dbCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, label
); 
 317         CssmClient::Key copiedKey
; 
 318         if (!dbCursor
->nextKey(NULL
, copiedKey
, uniqueId
)) 
 319                 MacOSError::throwMe(errSecItemNotFound
); 
 321         // Set the initial label, application label, and application tag (if provided) 
 323                 DbAttributes newDbAttributes
; 
 324                 SSDbCursor 
otherDbCursor(ssDb
, 1); 
 325                 otherDbCursor
->recordType(recordType()); 
 326                 bool checkForDuplicates 
= false; 
 328                 for (UInt32 index
=0; index 
< attrList
->count
; index
++) { 
 329                         SecKeychainAttribute attr 
= attrList
->attr
[index
]; 
 330                         CssmData 
attrData(attr
.data
, attr
.length
); 
 331                         if (attr
.tag 
== kSecKeyPrintName
) { 
 332                                 newDbAttributes
.add(kInfoKeyPrintName
, attrData
); 
 334                         if (attr
.tag 
== kSecKeyLabel
) { 
 335                                 newDbAttributes
.add(kInfoKeyLabel
, attrData
); 
 336                                 otherDbCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, attrData
); 
 337                                 checkForDuplicates 
= true; 
 339                         if (attr
.tag 
== kSecKeyApplicationTag
) { 
 340                                 newDbAttributes
.add(kInfoKeyApplicationTag
, attrData
); 
 341                                 otherDbCursor
->add(CSSM_DB_EQUAL
, kInfoKeyApplicationTag
, attrData
); 
 342                                 checkForDuplicates 
= true; 
 346                 DbAttributes otherDbAttributes
; 
 347                 DbUniqueRecord otherUniqueId
; 
 348                 CssmClient::Key otherKey
; 
 351                         if (checkForDuplicates 
&& otherDbCursor
->nextKey(&otherDbAttributes
, otherKey
, otherUniqueId
)) 
 352                                 MacOSError::throwMe(errSecDuplicateItem
); 
 354                         uniqueId
->modify(recordType(), &newDbAttributes
, NULL
, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
); 
 358                         // clean up after trying to insert a duplicate key 
 359                         uniqueId
->deleteRecord (); 
 364         /* Set the acl and owner on the unwrapped key. */ 
 365         access
->setAccess(*unwrappedKey
, maker
); 
 367         /* Return a keychain item which represents the new key.  */ 
 368         Item 
item(keychain
->item(recordType(), uniqueId
)); 
 370     KCEventNotifier::PostKeychainEvent(kSecAddEvent
, keychain
, item
); 
 381 KeyItem::add(Keychain 
&keychain
) 
 383         MacOSError::throwMe(errSecUnimplemented
); 
 386 CssmClient::SSDbUniqueRecord
 
 387 KeyItem::ssDbUniqueRecord() 
 389         DbUniqueRecordImpl 
*impl 
= &*dbUniqueRecord(); 
 390         Security::CssmClient::SSDbUniqueRecordImpl 
*simpl 
= dynamic_cast<Security::CssmClient::SSDbUniqueRecordImpl 
*>(impl
); 
 393                 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
); 
 396         return CssmClient::SSDbUniqueRecord(simpl
); 
 402     StLock
<Mutex
>_(mMutex
); 
 405                 CssmClient::SSDbUniqueRecord 
uniqueId(ssDbUniqueRecord()); 
 406                 CssmDataContainer 
dataBlob(uniqueId
->allocator()); 
 407                 uniqueId
->get(NULL
, &dataBlob
); 
 408                 mKey 
= CssmClient::Key(uniqueId
->database()->csp(), *reinterpret_cast<CssmKey 
*>(dataBlob
.Data
)); 
 421 const CSSM_X509_ALGORITHM_IDENTIFIER
& 
 422 KeyItem::algorithmIdentifier() 
 426         CSSM_KEY_TYPE algorithm
 
 427                 CSSM_KEY_PTR cssmKey 
=  (CSSM_KEY_PTR
)thisData
->Data
; 
 429         static void printKeyHeader( 
 430         const CSSM_KEYHEADER 
&hdr
) 
 432         printf("   Algorithm       : "); 
 433         switch(hdr
.AlgorithmId
) { 
 434 CSSM_X509_ALGORITHM_IDENTIFIER algID
; 
 436 CSSM_OID 
*CL_algToOid( 
 437         CSSM_ALGORITHMS algId
) 
 438 typedef struct cssm_x509_algorithm_identifier 
{ 
 440     CSSM_DATA parameters
; 
 441 } CSSM_X509_ALGORITHM_IDENTIFIER
, *CSSM_X509_ALGORITHM_IDENTIFIER_PTR
; 
 448  * itemID, used to locate Extended Attributes, is the public key hash for keys. 
 450 const CssmData 
&KeyItem::itemID() 
 452         if(mPubKeyHash
.length() == 0) { 
 454                  * Fetch the attribute from disk. 
 456                 UInt32 tag 
= kSecKeyLabel
; 
 458                 SecKeychainAttributeInfo attrInfo 
= {1, &tag
, &format
}; 
 459                 SecKeychainAttributeList 
*attrList 
= NULL
; 
 460                 getAttributesAndData(&attrInfo
, NULL
, &attrList
, NULL
, NULL
); 
 461                 if((attrList 
== NULL
) || (attrList
->count 
!= 1)) { 
 462                         MacOSError::throwMe(errSecNoSuchAttr
); 
 464                 mPubKeyHash
.copy(attrList
->attr
->data
, attrList
->attr
->length
); 
 465                 freeAttributesAndData(attrList
, NULL
); 
 472 KeyItem::strengthInBits(const CSSM_X509_ALGORITHM_IDENTIFIER 
*algid
) 
 474         // @@@ Make a context with key based on algid and use that to get the effective keysize and not just the logical one. 
 475         CSSM_KEY_SIZE keySize 
= {}; 
 476         CSSM_RETURN rv 
= CSSM_QueryKeySizeInBits (csp()->handle(), 
 483         return keySize
.LogicalKeySizeInBits
; 
 486 const AccessCredentials 
* 
 487 KeyItem::getCredentials( 
 488         CSSM_ACL_AUTHORIZATION_TAG operation
, 
 489         SecCredentialType credentialType
) 
 491         // @@@ Fix this to actually examine the ACL for this key and consider operation and do the right thing. 
 492         //AutoAclEntryInfoList aclInfos; 
 493         //key()->getAcl(aclInfos); 
 495         bool smartcard 
= keychain() != NULL 
? (keychain()->database()->dl()->guid() == gGuidAppleSdCSPDL
) : false; 
 498         switch (credentialType
) 
 500         case kSecCredentialTypeDefault
: 
 501                 return smartcard
?globals().smartcardItemCredentials():globals().itemCredentials(); 
 502         case kSecCredentialTypeWithUI
: 
 503                 return smartcard
?globals().smartcardItemCredentials():factory
.promptCred(); 
 504         case kSecCredentialTypeNoUI
: 
 505                 return factory
.nullCred(); 
 507                 MacOSError::throwMe(errSecParam
); 
 512 KeyItem::operator == (KeyItem 
&other
) 
 517                 return this == &other
; 
 520         // If keychains are different, then keys are different 
 521         Keychain otherKeychain 
= other
.keychain(); 
 522         return (mKeychain 
&& otherKeychain 
&& (*mKeychain 
== *otherKeychain
)); 
 528         CSSM_ALGORITHMS algorithm
, 
 529         uint32 keySizeInBits
, 
 530         CSSM_CC_HANDLE contextHandle
, 
 531         CSSM_KEYUSE publicKeyUsage
, 
 532         uint32 publicKeyAttr
, 
 533         CSSM_KEYUSE privateKeyUsage
, 
 534         uint32 privateKeyAttr
, 
 535         SecPointer
<Access
> initialAccess
, 
 536         SecPointer
<KeyItem
> &outPublicKey
, 
 537         SecPointer
<KeyItem
> &outPrivateKey
) 
 539         bool freeKeys 
= false; 
 540         bool deleteContext 
= false; 
 542         if (!(keychain
->database()->dl()->subserviceMask() & CSSM_SERVICE_CSP
)) 
 543                 MacOSError::throwMe(errSecInvalidKeychain
); 
 545         SSDbImpl
* impl 
= dynamic_cast<SSDbImpl
*>(&(*keychain
->database())); 
 548                 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
); 
 552         CssmClient::CSP 
csp(keychain
->csp()); 
 553         CssmClient::CSP 
appleCsp(gGuidAppleCSP
); 
 555         // Generate a random label to use initially 
 556         CssmClient::Random 
random(appleCsp
, CSSM_ALGID_APPLE_YARROW
); 
 557         uint8 labelBytes
[20]; 
 558         CssmData 
label(labelBytes
, sizeof(labelBytes
)); 
 559         random
.generate(label
, (uint32
)label
.Length
); 
 561         // Create a Access::Maker for the initial owner of the private key. 
 562         ResourceControlContext rcc
; 
 563         memset(&rcc
, 0, sizeof(rcc
)); 
 565         // @@@ 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. 
 566         maker
.initialOwner(rcc
); 
 567         // Create the cred we need to manipulate the keys until we actually set a new access control for them. 
 568         const AccessCredentials 
*cred 
= maker
.cred(); 
 570         CSSM_KEY publicCssmKey
, privateCssmKey
; 
 571         memset(&publicCssmKey
, 0, sizeof(publicCssmKey
)); 
 572         memset(&privateCssmKey
, 0, sizeof(privateCssmKey
)); 
 574         CSSM_CC_HANDLE ccHandle 
= 0; 
 576         Item publicKeyItem
, privateKeyItem
; 
 581                                 ccHandle 
= contextHandle
; 
 584                         status 
= CSSM_CSP_CreateKeyGenContext(csp
->handle(), algorithm
, keySizeInBits
, NULL
, NULL
, NULL
, NULL
, NULL
, &ccHandle
); 
 586                                 CssmError::throwMe(status
); 
 587                         deleteContext 
= true; 
 590                 CSSM_DL_DB_HANDLE dldbHandle 
= ssDb
->handle(); 
 591                 CSSM_DL_DB_HANDLE_PTR dldbHandlePtr 
= &dldbHandle
; 
 592                 CSSM_CONTEXT_ATTRIBUTE contextAttributes 
= { CSSM_ATTRIBUTE_DL_DB_HANDLE
, sizeof(dldbHandle
), { (char *)dldbHandlePtr 
} }; 
 593                 status 
= CSSM_UpdateContextAttributes(ccHandle
, 1, &contextAttributes
); 
 595                         CssmError::throwMe(status
); 
 597                 // Generate the keypair 
 598                 status 
= CSSM_GenerateKeyPair(ccHandle
, publicKeyUsage
, publicKeyAttr
, &label
, &publicCssmKey
, privateKeyUsage
, privateKeyAttr
, &label
, &rcc
, &privateCssmKey
); 
 600                         CssmError::throwMe(status
); 
 603                 // Find the keys we just generated in the DL to get SecKeyRef's to them 
 604                 // so we can change the label to be the hash of the public key, and 
 605                 // fix up other attributes. 
 607                 // Look up public key in the DLDB. 
 608                 DbAttributes pubDbAttributes
; 
 609                 DbUniqueRecord pubUniqueId
; 
 610                 SSDbCursor 
dbPubCursor(ssDb
, 1); 
 611                 dbPubCursor
->recordType(CSSM_DL_DB_RECORD_PUBLIC_KEY
); 
 612                 dbPubCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, label
); 
 613                 CssmClient::Key publicKey
; 
 614                 if (!dbPubCursor
->nextKey(&pubDbAttributes
, publicKey
, pubUniqueId
)) 
 615                         MacOSError::throwMe(errSecItemNotFound
); 
 617                 // Look up private key in the DLDB. 
 618                 DbAttributes privDbAttributes
; 
 619                 DbUniqueRecord privUniqueId
; 
 620                 SSDbCursor 
dbPrivCursor(ssDb
, 1); 
 621                 dbPrivCursor
->recordType(CSSM_DL_DB_RECORD_PRIVATE_KEY
); 
 622                 dbPrivCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, label
); 
 623                 CssmClient::Key privateKey
; 
 624                 if (!dbPrivCursor
->nextKey(&privDbAttributes
, privateKey
, privUniqueId
)) 
 625                         MacOSError::throwMe(errSecItemNotFound
); 
 627                 // Convert reference public key to a raw key so we can use it 
 629                 CssmClient::WrapKey 
wrap(csp
, CSSM_ALGID_NONE
); 
 631                 CssmClient::Key rawPubKey 
= wrap(publicKey
); 
 633                 // Calculate the hash of the public key using the appleCSP. 
 634                 CssmClient::PassThrough 
passThrough(appleCsp
); 
 638                 /* Given a CSSM_KEY_PTR in any format, obtain the SHA-1 hash of the 
 639                 * associated key blob. 
 640                 * Key is specified in CSSM_CSP_CreatePassThroughContext. 
 641                 * Hash is allocated bythe CSP, in the App's memory, and returned 
 643                 passThrough
.key(rawPubKey
); 
 644                 passThrough(CSSM_APPLECSP_KEYDIGEST
, NULL
, &outData
); 
 645                 cssmData 
= reinterpret_cast<CssmData 
*>(outData
); 
 646                 CssmData 
&pubKeyHash 
= *cssmData
; 
 648                 auto_ptr
<string
>privDescription
; 
 649                 auto_ptr
<string
>pubDescription
; 
 651                         privDescription
.reset(new string(initialAccess
->promptDescription())); 
 652                         pubDescription
.reset(new string(initialAccess
->promptDescription())); 
 655                         /* this path taken if no promptDescription available, e.g., for complex ACLs */ 
 656                         privDescription
.reset(new string("Private key")); 
 657                         pubDescription
.reset(new string("Public key")); 
 660                 // Set the label of the public key to the public key hash. 
 661                 // Set the PrintName of the public key to the description in the acl. 
 662                 pubDbAttributes
.add(kInfoKeyLabel
, pubKeyHash
); 
 663                 pubDbAttributes
.add(kInfoKeyPrintName
, *pubDescription
); 
 664                 pubUniqueId
->modify(CSSM_DL_DB_RECORD_PUBLIC_KEY
, &pubDbAttributes
, NULL
, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
); 
 666                 // Set the label of the private key to the public key hash. 
 667                 // Set the PrintName of the private key to the description in the acl. 
 668                 privDbAttributes
.add(kInfoKeyLabel
, pubKeyHash
); 
 669                 privDbAttributes
.add(kInfoKeyPrintName
, *privDescription
); 
 670                 privUniqueId
->modify(CSSM_DL_DB_RECORD_PRIVATE_KEY
, &privDbAttributes
, NULL
, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
); 
 672                 // @@@ Not exception safe! 
 673                 csp
.allocator().free(cssmData
->Data
); 
 674                 csp
.allocator().free(cssmData
); 
 676                 // Finally fix the acl and owner of the private key to the specified access control settings. 
 677                 initialAccess
->setAccess(*privateKey
, maker
); 
 679                 if(publicKeyAttr 
& CSSM_KEYATTR_PUBLIC_KEY_ENCRYPT
) { 
 681                          * Make the public key acl completely open. 
 682                          * If the key was not encrypted, it already has a wide-open 
 683                          * ACL (though that is a feature of securityd; it's not 
 684                          * CDSA-specified behavior). 
 686                         SecPointer
<Access
> pubKeyAccess(new Access()); 
 687                         pubKeyAccess
->setAccess(*publicKey
, maker
); 
 690                 // Create keychain items which will represent the keys. 
 691                 publicKeyItem 
= keychain
->item(CSSM_DL_DB_RECORD_PUBLIC_KEY
, pubUniqueId
); 
 692                 privateKeyItem 
= keychain
->item(CSSM_DL_DB_RECORD_PRIVATE_KEY
, privUniqueId
); 
 694                 KeyItem
* impl 
= dynamic_cast<KeyItem
*>(&(*publicKeyItem
)); 
 697                         CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
); 
 702                 impl 
= dynamic_cast<KeyItem
*>(&(*privateKeyItem
)); 
 705                         CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
); 
 708                 outPrivateKey 
= impl
; 
 714                         // Delete the keys if something goes wrong so we don't end up with inaccessible keys in the database. 
 715                         CSSM_FreeKey(csp
->handle(), cred
, &publicCssmKey
, TRUE
); 
 716                         CSSM_FreeKey(csp
->handle(), cred
, &privateCssmKey
, TRUE
); 
 720                         CSSM_DeleteContext(ccHandle
); 
 727                 CSSM_FreeKey(csp
->handle(), NULL
, &publicCssmKey
, FALSE
); 
 728                 CSSM_FreeKey(csp
->handle(), NULL
, &privateCssmKey
, FALSE
); 
 732                 CSSM_DeleteContext(ccHandle
); 
 734         if (keychain 
&& publicKeyItem 
&& privateKeyItem
) 
 736                 keychain
->postEvent(kSecAddEvent
, publicKeyItem
); 
 737                 keychain
->postEvent(kSecAddEvent
, privateKeyItem
); 
 744         const CSSM_KEY 
&publicWrappedKey
, 
 745         const CSSM_KEY 
&privateWrappedKey
, 
 746         SecPointer
<Access
> initialAccess
, 
 747         SecPointer
<KeyItem
> &outPublicKey
, 
 748         SecPointer
<KeyItem
> &outPrivateKey
) 
 750         bool freePublicKey 
= false; 
 751         bool freePrivateKey 
= false; 
 752         bool deleteContext 
= false; 
 754         if (!(keychain
->database()->dl()->subserviceMask() & CSSM_SERVICE_CSP
)) 
 755                 MacOSError::throwMe(errSecInvalidKeychain
); 
 757         SSDbImpl
* impl 
= dynamic_cast<SSDbImpl 
*>(&(*keychain
->database())); 
 760                 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
); 
 764         CssmClient::CSP 
csp(keychain
->csp()); 
 765         CssmClient::CSP 
appleCsp(gGuidAppleCSP
); 
 767         // Create a Access::Maker for the initial owner of the private key. 
 768         ResourceControlContext rcc
; 
 769         memset(&rcc
, 0, sizeof(rcc
)); 
 770         Access::Maker 
maker(Allocator::standard(), Access::Maker::kAnyMakerType
); 
 771         // @@@ Potentially provide a credential argument which allows us to unwrap keys in the csp. 
 772         // Currently the CSP lets anyone do this, but we might restrict this in the future, e.g. 
 773         // a smartcard could require out of band pin entry before a key can be generated. 
 774         maker
.initialOwner(rcc
); 
 775         // Create the cred we need to manipulate the keys until we actually set a new access control for them. 
 776         const AccessCredentials 
*cred 
= maker
.cred(); 
 778         CSSM_KEY publicCssmKey
, privateCssmKey
; 
 779         memset(&publicCssmKey
, 0, sizeof(publicCssmKey
)); 
 780         memset(&privateCssmKey
, 0, sizeof(privateCssmKey
)); 
 782         CSSM_CC_HANDLE ccHandle 
= 0; 
 784         Item publicKeyItem
, privateKeyItem
; 
 789                 // Calculate the hash of the public key using the appleCSP. 
 790                 CssmClient::PassThrough 
passThrough(appleCsp
); 
 794                 /* Given a CSSM_KEY_PTR in any format, obtain the SHA-1 hash of the 
 795                 * associated key blob. 
 796                 * Key is specified in CSSM_CSP_CreatePassThroughContext. 
 797                 * Hash is allocated bythe CSP, in the App's memory, and returned 
 799                 passThrough
.key(&publicWrappedKey
); 
 800                 passThrough(CSSM_APPLECSP_KEYDIGEST
, NULL
, &outData
); 
 801                 cssmData 
= reinterpret_cast<CssmData 
*>(outData
); 
 802                 CssmData 
&pubKeyHash 
= *cssmData
; 
 804                 status 
= CSSM_CSP_CreateSymmetricContext(csp
->handle(), publicWrappedKey
.KeyHeader
.WrapAlgorithmId
, CSSM_ALGMODE_NONE
, NULL
, NULL
, NULL
, CSSM_PADDING_NONE
, NULL
, &ccHandle
); 
 806                         CssmError::throwMe(status
); 
 807                 deleteContext 
= true; 
 809                 CSSM_DL_DB_HANDLE dldbHandle 
= ssDb
->handle(); 
 810                 CSSM_DL_DB_HANDLE_PTR dldbHandlePtr 
= &dldbHandle
; 
 811                 CSSM_CONTEXT_ATTRIBUTE contextAttributes 
= { CSSM_ATTRIBUTE_DL_DB_HANDLE
, sizeof(dldbHandle
), { (char *)dldbHandlePtr 
} }; 
 812                 status 
= CSSM_UpdateContextAttributes(ccHandle
, 1, &contextAttributes
); 
 814                         CssmError::throwMe(status
); 
 816                 // Unwrap the the keys 
 817                 CSSM_DATA descriptiveData 
= {0, NULL
}; 
 819                 status 
= CSSM_UnwrapKey( 
 823                         publicWrappedKey
.KeyHeader
.KeyUsage
, 
 824                         publicWrappedKey
.KeyHeader
.KeyAttr 
| CSSM_KEYATTR_PERMANENT
, 
 831                         CssmError::throwMe(status
); 
 832                 freePublicKey 
= true; 
 834                 if (descriptiveData
.Data 
!= NULL
) 
 835                         free (descriptiveData
.Data
); 
 837                 status 
= CSSM_UnwrapKey( 
 841                         privateWrappedKey
.KeyHeader
.KeyUsage
, 
 842                         privateWrappedKey
.KeyHeader
.KeyAttr 
| CSSM_KEYATTR_PERMANENT
, 
 849                         CssmError::throwMe(status
); 
 851                 if (descriptiveData
.Data 
!= NULL
) 
 852                         free (descriptiveData
.Data
); 
 854                 freePrivateKey 
= true; 
 856                 // Find the keys we just generated in the DL to get SecKeyRefs to them 
 857                 // so we can change the label to be the hash of the public key, and 
 858                 // fix up other attributes. 
 860                 // Look up public key in the DLDB. 
 861                 DbAttributes pubDbAttributes
; 
 862                 DbUniqueRecord pubUniqueId
; 
 863                 SSDbCursor 
dbPubCursor(ssDb
, 1); 
 864                 dbPubCursor
->recordType(CSSM_DL_DB_RECORD_PUBLIC_KEY
); 
 865                 dbPubCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, pubKeyHash
); 
 866                 CssmClient::Key publicKey
; 
 867                 if (!dbPubCursor
->nextKey(&pubDbAttributes
, publicKey
, pubUniqueId
)) 
 868                         MacOSError::throwMe(errSecItemNotFound
); 
 870                 // Look up private key in the DLDB. 
 871                 DbAttributes privDbAttributes
; 
 872                 DbUniqueRecord privUniqueId
; 
 873                 SSDbCursor 
dbPrivCursor(ssDb
, 1); 
 874                 dbPrivCursor
->recordType(CSSM_DL_DB_RECORD_PRIVATE_KEY
); 
 875                 dbPrivCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, pubKeyHash
); 
 876                 CssmClient::Key privateKey
; 
 877                 if (!dbPrivCursor
->nextKey(&privDbAttributes
, privateKey
, privUniqueId
)) 
 878                         MacOSError::throwMe(errSecItemNotFound
); 
 880                 // @@@ Not exception safe! 
 881                 csp
.allocator().free(cssmData
->Data
); 
 882                 csp
.allocator().free(cssmData
); 
 884                 auto_ptr
<string
>privDescription
; 
 885                 auto_ptr
<string
>pubDescription
; 
 887                         privDescription
.reset(new string(initialAccess
->promptDescription())); 
 888                         pubDescription
.reset(new string(initialAccess
->promptDescription())); 
 891                         /* this path taken if no promptDescription available, e.g., for complex ACLs */ 
 892                         privDescription
.reset(new string("Private key")); 
 893                         pubDescription
.reset(new string("Public key")); 
 896                 // Set the label of the public key to the public key hash. 
 897                 // Set the PrintName of the public key to the description in the acl. 
 898                 pubDbAttributes
.add(kInfoKeyPrintName
, *pubDescription
); 
 899                 pubUniqueId
->modify(CSSM_DL_DB_RECORD_PUBLIC_KEY
, &pubDbAttributes
, NULL
, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
); 
 901                 // Set the label of the private key to the public key hash. 
 902                 // Set the PrintName of the private key to the description in the acl. 
 903                 privDbAttributes
.add(kInfoKeyPrintName
, *privDescription
); 
 904                 privUniqueId
->modify(CSSM_DL_DB_RECORD_PRIVATE_KEY
, &privDbAttributes
, NULL
, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
); 
 906                 // Finally fix the acl and owner of the private key to the specified access control settings. 
 907                 initialAccess
->setAccess(*privateKey
, maker
); 
 909                 // Make the public key acl completely open 
 910                 SecPointer
<Access
> pubKeyAccess(new Access()); 
 911                 pubKeyAccess
->setAccess(*publicKey
, maker
); 
 913                 // Create keychain items which will represent the keys. 
 914                 publicKeyItem 
= keychain
->item(CSSM_DL_DB_RECORD_PUBLIC_KEY
, pubUniqueId
); 
 915                 privateKeyItem 
= keychain
->item(CSSM_DL_DB_RECORD_PRIVATE_KEY
, privUniqueId
); 
 917                 KeyItem
* impl 
= dynamic_cast<KeyItem
*>(&(*publicKeyItem
)); 
 920                         CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
); 
 925                 impl 
= dynamic_cast<KeyItem
*>(&(*privateKeyItem
)); 
 928                         CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
); 
 930                 outPrivateKey 
= impl
; 
 935                         CSSM_FreeKey(csp
->handle(), cred
, &publicCssmKey
, TRUE
); 
 937                         CSSM_FreeKey(csp
->handle(), cred
, &privateCssmKey
, TRUE
); 
 940                         CSSM_DeleteContext(ccHandle
); 
 946                 CSSM_FreeKey(csp
->handle(), cred
, &publicCssmKey
, FALSE
); 
 948                 CSSM_FreeKey(csp
->handle(), cred
, &privateCssmKey
, FALSE
); 
 951                 CSSM_DeleteContext(ccHandle
); 
 953         if (keychain 
&& publicKeyItem 
&& privateKeyItem
) 
 955                 KCEventNotifier::PostKeychainEvent(kSecAddEvent
, keychain
, publicKeyItem
); 
 956                 KCEventNotifier::PostKeychainEvent(kSecAddEvent
, keychain
, privateKeyItem
); 
 961 KeyItem::generateWithAttributes(const SecKeychainAttributeList 
*attrList
, 
 963         CSSM_ALGORITHMS algorithm
, 
 964         uint32 keySizeInBits
, 
 965         CSSM_CC_HANDLE contextHandle
, 
 966         CSSM_KEYUSE keyUsage
, 
 968         SecPointer
<Access
> initialAccess
) 
 970         CssmClient::CSP 
appleCsp(gGuidAppleCSP
); 
 971         CssmClient::CSP 
csp(NULL
); 
 973         uint8 labelBytes
[20]; 
 974         CssmData 
label(labelBytes
, sizeof(labelBytes
)); 
 975         bool freeKey 
= false; 
 976         bool deleteContext 
= false; 
 977         const CSSM_DATA 
*plabel 
= NULL
; 
 981                 if (!(keychain
->database()->dl()->subserviceMask() & CSSM_SERVICE_CSP
)) 
 982                         MacOSError::throwMe(errSecInvalidKeychain
); 
 984                 SSDbImpl
* impl 
= dynamic_cast<SSDbImpl 
*>(&(*keychain
->database())); 
 987                         CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
); 
 991                 csp 
= keychain
->csp(); 
 993                 // Generate a random label to use initially 
 994                 CssmClient::Random 
random(appleCsp
, CSSM_ALGID_APPLE_YARROW
); 
 995                 random
.generate(label
, (uint32
)label
.Length
); 
1000                 // Not a persistent key so create it in the regular csp 
1004         // Create a Access::Maker for the initial owner of the private key. 
1005         ResourceControlContext 
*prcc 
= NULL
, rcc
; 
1006         const AccessCredentials 
*cred 
= NULL
; 
1007         Access::Maker maker
; 
1008         if (keychain 
&& initialAccess
) 
1010                 memset(&rcc
, 0, sizeof(rcc
)); 
1011                 // @@@ Potentially provide a credential argument which allows us to generate keys in the csp. 
1012                 // Currently the CSP lets anyone do this, but we might restrict this in the future, e.g. a smartcard 
1013                 // could require out-of-band pin entry before a key can be generated. 
1014                 maker
.initialOwner(rcc
); 
1015                 // Create the cred we need to manipulate the keys until we actually set a new access control for them. 
1016                 cred 
= maker
.cred(); 
1022         CSSM_CC_HANDLE ccHandle 
= 0; 
1029                         ccHandle 
= contextHandle
; 
1032                         status 
= CSSM_CSP_CreateKeyGenContext(csp
->handle(), algorithm
, keySizeInBits
, NULL
, NULL
, NULL
, NULL
, NULL
, &ccHandle
); 
1034                                 CssmError::throwMe(status
); 
1035                         deleteContext 
= true; 
1040                         CSSM_DL_DB_HANDLE dldbHandle 
= ssDb
->handle(); 
1041                         CSSM_DL_DB_HANDLE_PTR dldbHandlePtr 
= &dldbHandle
; 
1042                         CSSM_CONTEXT_ATTRIBUTE contextAttributes 
= { CSSM_ATTRIBUTE_DL_DB_HANDLE
, sizeof(dldbHandle
), { (char *)dldbHandlePtr 
} }; 
1043                         status 
= CSSM_UpdateContextAttributes(ccHandle
, 1, &contextAttributes
); 
1045                                 CssmError::throwMe(status
); 
1047                         keyAttr 
|= CSSM_KEYATTR_PERMANENT
; 
1051                 status 
= CSSM_GenerateKey(ccHandle
, keyUsage
, keyAttr
, plabel
, prcc
, &cssmKey
); 
1053                         CssmError::throwMe(status
); 
1058                         // Find the key we just generated in the DL and get a SecKeyRef 
1059                         // so we can specify the label attribute(s) and initial ACL. 
1061                         // Look up key in the DLDB. 
1062                         DbAttributes dbAttributes
; 
1063                         DbUniqueRecord uniqueId
; 
1064                         SSDbCursor 
dbCursor(ssDb
, 1); 
1065                         dbCursor
->recordType(CSSM_DL_DB_RECORD_SYMMETRIC_KEY
); 
1066                         dbCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, label
); 
1067                         CssmClient::Key key
; 
1068                         if (!dbCursor
->nextKey(&dbAttributes
, key
, uniqueId
)) 
1069                                 MacOSError::throwMe(errSecItemNotFound
); 
1071                         // Set the initial label, application label, and application tag (if provided) 
1073                                 DbAttributes newDbAttributes
; 
1074                                 SSDbCursor 
otherDbCursor(ssDb
, 1); 
1075                                 otherDbCursor
->recordType(CSSM_DL_DB_RECORD_SYMMETRIC_KEY
); 
1076                                 bool checkForDuplicates 
= false; 
1078                                 for (UInt32 index
=0; index 
< attrList
->count
; index
++) { 
1079                                         SecKeychainAttribute attr 
= attrList
->attr
[index
]; 
1080                                         CssmData 
attrData(attr
.data
, attr
.length
); 
1081                                         if (attr
.tag 
== kSecKeyPrintName
) { 
1082                                                 newDbAttributes
.add(kInfoKeyPrintName
, attrData
); 
1084                                         if (attr
.tag 
== kSecKeyLabel
) { 
1085                                                 newDbAttributes
.add(kInfoKeyLabel
, attrData
); 
1086                                                 otherDbCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, attrData
); 
1087                                                 checkForDuplicates 
= true; 
1089                                         if (attr
.tag 
== kSecKeyApplicationTag
) { 
1090                                                 newDbAttributes
.add(kInfoKeyApplicationTag
, attrData
); 
1091                                                 otherDbCursor
->add(CSSM_DB_EQUAL
, kInfoKeyApplicationTag
, attrData
); 
1092                                                 checkForDuplicates 
= true; 
1096                                 DbAttributes otherDbAttributes
; 
1097                                 DbUniqueRecord otherUniqueId
; 
1098                                 CssmClient::Key otherKey
; 
1099                                 if (checkForDuplicates 
&& otherDbCursor
->nextKey(&otherDbAttributes
, otherKey
, otherUniqueId
)) 
1100                                         MacOSError::throwMe(errSecDuplicateItem
); 
1102                                 uniqueId
->modify(CSSM_DL_DB_RECORD_SYMMETRIC_KEY
, &newDbAttributes
, NULL
, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
); 
1105                         // Finally, fix the acl and owner of the key to the specified access control settings. 
1107                                 initialAccess
->setAccess(*key
, maker
); 
1109                         // Create keychain item which will represent the key. 
1110                         keyItem 
= keychain
->item(CSSM_DL_DB_RECORD_SYMMETRIC_KEY
, uniqueId
); 
1114                         CssmClient::Key 
tempKey(csp
, cssmKey
); 
1115                         keyItem 
= new KeyItem(tempKey
); 
1122                         // Delete the key if something goes wrong so we don't end up with inaccessible keys in the database. 
1123                         CSSM_FreeKey(csp
->handle(), cred
, &cssmKey
, TRUE
); 
1127                         CSSM_DeleteContext(ccHandle
); 
1134                 CSSM_FreeKey(csp
->handle(), NULL
, &cssmKey
, FALSE
); 
1138                 CSSM_DeleteContext(ccHandle
); 
1140         if (keychain 
&& keyItem
) 
1141                 keychain
->postEvent(kSecAddEvent
, keyItem
); 
1143         KeyItem
* item 
= dynamic_cast<KeyItem
*>(&*keyItem
); 
1146                 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
); 
1153 KeyItem::generate(Keychain keychain
, 
1154         CSSM_ALGORITHMS algorithm
, 
1155         uint32 keySizeInBits
, 
1156         CSSM_CC_HANDLE contextHandle
, 
1157         CSSM_KEYUSE keyUsage
, 
1159         SecPointer
<Access
> initialAccess
) 
1161         return KeyItem::generateWithAttributes(NULL
, keychain
, 
1162                 algorithm
, keySizeInBits
, contextHandle
, 
1163                 keyUsage
, keyAttr
, initialAccess
); 
1167 void KeyItem::RawSign(SecPadding padding
, CSSM_DATA dataToSign
, const AccessCredentials 
*credentials
, CSSM_DATA
& signature
) 
1169         CSSM_ALGORITHMS baseAlg 
= key()->header().algorithm(); 
1171     if ((baseAlg 
!= CSSM_ALGID_RSA
) && (baseAlg 
!= CSSM_ALGID_ECDSA
)) 
1173                 MacOSError::throwMe(errSecParam
); 
1176         CSSM_ALGORITHMS paddingAlg 
= CSSM_PADDING_PKCS1
; 
1180                 case kSecPaddingPKCS1
: 
1182                         paddingAlg 
= CSSM_PADDING_PKCS1
; 
1186                 case kSecPaddingPKCS1MD2
: 
1188                         baseAlg 
= CSSM_ALGID_MD2WithRSA
; 
1192                 case kSecPaddingPKCS1MD5
: 
1194                         baseAlg 
= CSSM_ALGID_MD5WithRSA
; 
1198                 case kSecPaddingPKCS1SHA1
: 
1200                         baseAlg 
= CSSM_ALGID_SHA1WithRSA
; 
1204         case kSecPaddingSigRaw
: 
1206             paddingAlg 
= CSSM_PADDING_SIGRAW
; 
1212                         paddingAlg 
= CSSM_PADDING_NONE
; 
1217         Sign 
signContext(csp(), baseAlg
); 
1218         signContext
.key(key()); 
1219         signContext
.cred(credentials
); 
1220     // Fields required for CSSM_CSP_CreateSignatureContext set above.  Using add instead of set ensures 
1221     // that the context is constructed before the set is attempted, which would fail silently otherwise. 
1222     signContext
.add(CSSM_ATTRIBUTE_PADDING
, paddingAlg
); 
1224         CssmData 
data(dataToSign
.Data
, dataToSign
.Length
); 
1225         signContext
.sign(data
); 
1227     CssmData 
sig(signature
.Data
, signature
.Length
); 
1228         signContext(sig
); // yes, this is an accessor.  Believe it, or not. 
1229     signature
.Length 
= sig
.length(); 
1234 void KeyItem::RawVerify(SecPadding padding
, CSSM_DATA dataToVerify
, const AccessCredentials 
*credentials
, CSSM_DATA sig
) 
1236         CSSM_ALGORITHMS baseAlg 
= key()->header().algorithm(); 
1237     if ((baseAlg 
!= CSSM_ALGID_RSA
) && (baseAlg 
!= CSSM_ALGID_ECDSA
)) 
1239                 MacOSError::throwMe(errSecParam
); 
1242         CSSM_ALGORITHMS paddingAlg 
= CSSM_PADDING_PKCS1
; 
1246                 case kSecPaddingPKCS1
: 
1248                         paddingAlg 
= CSSM_PADDING_PKCS1
; 
1252                 case kSecPaddingPKCS1MD2
: 
1254                         baseAlg 
= CSSM_ALGID_MD2WithRSA
; 
1258                 case kSecPaddingPKCS1MD5
: 
1260                         baseAlg 
= CSSM_ALGID_MD5WithRSA
; 
1264                 case kSecPaddingPKCS1SHA1
: 
1266                         baseAlg 
= CSSM_ALGID_SHA1WithRSA
; 
1270         case kSecPaddingSigRaw
: 
1272             paddingAlg 
= CSSM_PADDING_SIGRAW
; 
1278                         paddingAlg 
= CSSM_PADDING_NONE
; 
1283         Verify 
verifyContext(csp(), baseAlg
); 
1284         verifyContext
.key(key()); 
1285         verifyContext
.cred(credentials
); 
1286     // Fields required for CSSM_CSP_CreateSignatureContext set above.  Using add instead of set ensures 
1287     // that the context is constructed before the set is attempted, which would fail silently otherwise. 
1288     verifyContext
.add(CSSM_ATTRIBUTE_PADDING
, paddingAlg
); 
1290         CssmData 
data(dataToVerify
.Data
, dataToVerify
.Length
); 
1291         CssmData 
signature(sig
.Data
, sig
.Length
); 
1292         verifyContext
.verify(data
, signature
); 
1297 void KeyItem::Encrypt(SecPadding padding
, CSSM_DATA dataToEncrypt
, const AccessCredentials 
*credentials
, CSSM_DATA
& encryptedData
) 
1299         CSSM_ALGORITHMS baseAlg 
= key()->header().algorithm(); 
1300         if (baseAlg 
!= CSSM_ALGID_RSA
) 
1302                 MacOSError::throwMe(errSecParam
); 
1305         CSSM_ALGORITHMS paddingAlg 
= CSSM_PADDING_PKCS1
; 
1309                 case kSecPaddingPKCS1
: 
1311                         paddingAlg 
= CSSM_PADDING_PKCS1
; 
1317                         paddingAlg 
= CSSM_PADDING_NONE
; 
1322         CssmClient::Encrypt 
encryptContext(csp(), baseAlg
); 
1323         encryptContext
.key(key()); 
1324         encryptContext
.padding(paddingAlg
); 
1325         encryptContext
.cred(credentials
); 
1327         CssmData 
inData(dataToEncrypt
.Data
, dataToEncrypt
.Length
); 
1328         CssmData 
outData(encryptedData
.Data
, encryptedData
.Length
); 
1329         CssmData 
remData((void*) NULL
, 0); 
1331         encryptedData
.Length 
= encryptContext
.encrypt(inData
, outData
, remData
); 
1336 void KeyItem::Decrypt(SecPadding padding
, CSSM_DATA dataToDecrypt
, const AccessCredentials 
*credentials
, CSSM_DATA
& decryptedData
) 
1338         CSSM_ALGORITHMS baseAlg 
= key()->header().algorithm(); 
1339         if (baseAlg 
!= CSSM_ALGID_RSA
) 
1341                 MacOSError::throwMe(errSecParam
); 
1344         CSSM_ALGORITHMS paddingAlg 
= CSSM_PADDING_PKCS1
; 
1348                 case kSecPaddingPKCS1
: 
1350                         paddingAlg 
= CSSM_PADDING_PKCS1
; 
1357                         paddingAlg 
= CSSM_PADDING_NONE
; 
1362         CssmClient::Decrypt 
decryptContext(csp(), baseAlg
); 
1363         decryptContext
.key(key()); 
1364         decryptContext
.padding(paddingAlg
); 
1365         decryptContext
.cred(credentials
); 
1367         CssmData 
inData(dataToDecrypt
.Data
, dataToDecrypt
.Length
); 
1368         CssmData 
outData(decryptedData
.Data
, decryptedData
.Length
); 
1369         CssmData 
remData((void*) NULL
, 0); 
1370         decryptedData
.Length 
= decryptContext
.decrypt(inData
, outData
, remData
); 
1371     if (remData
.Data 
!= NULL
) 
1377 CFHashCode 
KeyItem::hash() 
1379         CFHashCode result 
= 0; 
1380         const CSSM_KEY 
*cssmKey 
= key(); 
1381         if (NULL 
!= cssmKey
) 
1383                 unsigned char digest
[CC_SHA256_DIGEST_LENGTH
]; 
1385                 CFIndex size_of_data 
= sizeof(CSSM_KEYHEADER
) +  cssmKey
->KeyData
.Length
; 
1387                 CFMutableDataRef temp_cfdata 
= CFDataCreateMutable(kCFAllocatorDefault
, size_of_data
); 
1388                 if (NULL 
== temp_cfdata
) 
1393                 CFDataAppendBytes(temp_cfdata
, (const UInt8 
*)cssmKey
, sizeof(CSSM_KEYHEADER
)); 
1394                 CFDataAppendBytes(temp_cfdata
, cssmKey
->KeyData
.Data
, cssmKey
->KeyData
.Length
); 
1396                 if (size_of_data 
< 80) 
1398                         // If it is less than 80 bytes then CFData can be used 
1399                         result 
= CFHash(temp_cfdata
); 
1400                         CFRelease(temp_cfdata
); 
1402                 // CFData truncates its hash value to 80 bytes. ???? 
1403                 // In order to do the 'right thing' a SHA 256 hash will be used to 
1404                 // include all of the data 
1407                         memset(digest
, 0, CC_SHA256_DIGEST_LENGTH
); 
1409                         CC_SHA256((const void *)CFDataGetBytePtr(temp_cfdata
), (CC_LONG
)CFDataGetLength(temp_cfdata
), digest
); 
1411                         CFDataRef data_to_hash 
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, 
1412                                 (const UInt8 
*)digest
, CC_SHA256_DIGEST_LENGTH
, kCFAllocatorNull
); 
1413                         result 
= CFHash(data_to_hash
); 
1414                         CFRelease(data_to_hash
); 
1415                         CFRelease(temp_cfdata
);