2 * Copyright (c) 2002-2004 Apple Computer, 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 static CSSM_DB_NAME_ATTR(kInfoKeyPrintName
, kSecKeyPrintName
, (char*) "PrintName", 0, NULL
, BLOB
);
44 static CSSM_DB_NAME_ATTR(kInfoKeyLabel
, kSecKeyLabel
, (char*) "Label", 0, NULL
, BLOB
);
45 static CSSM_DB_NAME_ATTR(kInfoKeyApplicationTag
, kSecKeyApplicationTag
, (char*) "ApplicationTag", 0, NULL
, BLOB
);
47 using namespace KeychainCore
;
48 using namespace CssmClient
;
50 KeyItem::KeyItem(const Keychain
&keychain
, const PrimaryKey
&primaryKey
, const CssmClient::DbUniqueRecord
&uniqueId
) :
51 ItemImpl(keychain
, primaryKey
, uniqueId
),
54 mPubKeyHash(Allocator::standard())
58 KeyItem::KeyItem(const Keychain
&keychain
, const PrimaryKey
&primaryKey
) :
59 ItemImpl(keychain
, primaryKey
),
62 mPubKeyHash(Allocator::standard())
66 KeyItem
* KeyItem::make(const Keychain
&keychain
, const PrimaryKey
&primaryKey
, const CssmClient::DbUniqueRecord
&uniqueId
)
68 KeyItem
* k
= new KeyItem(keychain
, primaryKey
, uniqueId
);
69 keychain
->addItem(primaryKey
, k
);
75 KeyItem
* KeyItem::make(const Keychain
&keychain
, const PrimaryKey
&primaryKey
)
77 KeyItem
* k
= new KeyItem(keychain
, primaryKey
);
78 keychain
->addItem(primaryKey
, k
);
84 KeyItem::KeyItem(KeyItem
&keyItem
) :
88 mPubKeyHash(Allocator::standard())
90 // @@@ this doesn't work for keys that are not in a keychain.
93 KeyItem::KeyItem(const CssmClient::Key
&key
) :
94 ItemImpl(key
->keyClass() + CSSM_DL_DB_RECORD_PUBLIC_KEY
, (OSType
)0, (UInt32
)0, (const void*)NULL
),
97 mPubKeyHash(Allocator::standard())
99 if (key
->keyClass() > CSSM_KEYCLASS_SESSION_KEY
)
100 MacOSError::throwMe(errSecParam
);
114 KeyItem::copyTo(const Keychain
&keychain
, Access
*newAccess
)
116 if (!(keychain
->database()->dl()->subserviceMask() & CSSM_SERVICE_CSP
))
117 MacOSError::throwMe(errSecInvalidKeychain
);
119 /* Get the destination keychain's db. */
120 SSDbImpl
* dbImpl
= dynamic_cast<SSDbImpl
*>(&(*keychain
->database()));
123 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
);
128 /* Make sure mKey is valid. */
129 const CSSM_KEY
*cssmKey
= key();
130 if (cssmKey
&& (0==(cssmKey
->KeyHeader
.KeyAttr
& CSSM_KEYATTR_EXTRACTABLE
)))
132 MacOSError::throwMe(errSecDataNotAvailable
);
135 // Generate a random label to use initially
136 CssmClient::CSP
appleCsp(gGuidAppleCSP
);
137 CssmClient::Random
random(appleCsp
, CSSM_ALGID_APPLE_YARROW
);
138 uint8 labelBytes
[20];
139 CssmData
label(labelBytes
, sizeof(labelBytes
));
140 random
.generate(label
, (uint32
)label
.Length
);
142 /* Set up the ACL for the new key. */
143 SecPointer
<Access
> access
;
147 access
= new Access(*mKey
);
149 /* Generate a random 3DES wrapping Key. */
150 CssmClient::GenerateKey
genKey(csp(), CSSM_ALGID_3DES_3KEY
, 192);
151 CssmClient::Key
wrappingKey(genKey(KeySpec(CSSM_KEYUSE_WRAP
| CSSM_KEYUSE_UNWRAP
,
152 CSSM_KEYATTR_EXTRACTABLE
/* | CSSM_KEYATTR_RETURN_DATA */)));
154 /* make a random IV */
156 CssmData
iv(ivBytes
, sizeof(ivBytes
));
157 random
.generate(iv
, (uint32
)iv
.length());
159 /* Extract the key by wrapping it with the wrapping key. */
160 CssmClient::WrapKey
wrap(csp(), CSSM_ALGID_3DES_3KEY_EDE
);
161 wrap
.key(wrappingKey
);
162 wrap
.cred(getCredentials(CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED
, kSecCredentialTypeDefault
));
163 wrap
.mode(CSSM_ALGMODE_ECBPad
);
164 wrap
.padding(CSSM_PADDING_PKCS7
);
166 CssmClient::Key
wrappedKey(wrap(mKey
));
168 /* Unwrap the new key into the new Keychain. */
169 CssmClient::UnwrapKey
unwrap(keychain
->csp(), CSSM_ALGID_3DES_3KEY_EDE
);
170 unwrap
.key(wrappingKey
);
171 unwrap
.mode(CSSM_ALGMODE_ECBPad
);
172 unwrap
.padding(CSSM_PADDING_PKCS7
);
173 unwrap
.initVector(iv
);
175 /* Setup the dldbHandle in the context. */
176 unwrap
.add(CSSM_ATTRIBUTE_DL_DB_HANDLE
, ssDb
->handle());
178 /* Set up an initial aclEntry so we can change it after the unwrap. */
179 Access::Maker
maker(Allocator::standard(), Access::Maker::kAnyMakerType
);
180 ResourceControlContext rcc
;
181 maker
.initialOwner(rcc
, NULL
);
182 unwrap
.owner(rcc
.input());
184 /* Unwrap the key. */
185 uint32 usage
= mKey
->usage();
186 /* Work around csp brokeness where it sets all usage bits in the Keyheader when CSSM_KEYUSE_ANY is set. */
187 if (usage
& CSSM_KEYUSE_ANY
)
188 usage
= CSSM_KEYUSE_ANY
;
190 CssmClient::Key
unwrappedKey(unwrap(wrappedKey
, KeySpec(usage
,
191 (mKey
->attributes() | CSSM_KEYATTR_PERMANENT
) & ~(CSSM_KEYATTR_ALWAYS_SENSITIVE
| CSSM_KEYATTR_NEVER_EXTRACTABLE
),
194 /* Look up unwrapped key in the DLDB. */
195 DbUniqueRecord uniqueId
;
196 SSDbCursor
dbCursor(ssDb
, 1);
197 dbCursor
->recordType(recordType());
198 dbCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, label
);
199 CssmClient::Key copiedKey
;
200 if (!dbCursor
->nextKey(NULL
, copiedKey
, uniqueId
))
201 MacOSError::throwMe(errSecItemNotFound
);
203 /* Copy the Label, PrintName and ApplicationTag attributes from the old key to the new one. */
205 DbAttributes
oldDbAttributes(mUniqueId
->database(), 3);
206 oldDbAttributes
.add(kInfoKeyLabel
);
207 oldDbAttributes
.add(kInfoKeyPrintName
);
208 oldDbAttributes
.add(kInfoKeyApplicationTag
);
209 mUniqueId
->get(&oldDbAttributes
, NULL
);
212 uniqueId
->modify(recordType(), &oldDbAttributes
, NULL
, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
);
216 // clean up after trying to insert a duplicate key
217 uniqueId
->deleteRecord ();
221 /* Set the acl and owner on the unwrapped key. */
222 access
->setAccess(*unwrappedKey
, maker
);
224 /* Return a keychain item which represents the new key. */
225 Item
item(keychain
->item(recordType(), uniqueId
));
227 KCEventNotifier::PostKeychainEvent(kSecAddEvent
, keychain
, item
);
233 KeyItem::importTo(const Keychain
&keychain
, Access
*newAccess
, SecKeychainAttributeList
*attrList
)
235 if (!(keychain
->database()->dl()->subserviceMask() & CSSM_SERVICE_CSP
))
236 MacOSError::throwMe(errSecInvalidKeychain
);
238 /* Get the destination keychain's db. */
239 SSDbImpl
* dbImpl
= dynamic_cast<SSDbImpl
*>(&(*keychain
->database()));
241 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
);
245 /* Make sure mKey is valid. */
246 /* We can't call key() here, since we won't have a unique record id yet */
248 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
);
250 // Generate a random label to use initially
251 CssmClient::CSP
appleCsp(gGuidAppleCSP
);
252 CssmClient::Random
random(appleCsp
, CSSM_ALGID_APPLE_YARROW
);
253 uint8 labelBytes
[20];
254 CssmData
label(labelBytes
, sizeof(labelBytes
));
255 random
.generate(label
, (uint32
)label
.Length
);
257 /* Set up the ACL for the new key. */
258 SecPointer
<Access
> access
;
262 access
= new Access(*mKey
);
264 /* Generate a random 3DES wrapping Key. */
265 CssmClient::GenerateKey
genKey(csp(), CSSM_ALGID_3DES_3KEY
, 192);
266 CssmClient::Key
wrappingKey(genKey(KeySpec(CSSM_KEYUSE_WRAP
| CSSM_KEYUSE_UNWRAP
,
267 CSSM_KEYATTR_EXTRACTABLE
/* | CSSM_KEYATTR_RETURN_DATA */)));
269 /* make a random IV */
271 CssmData
iv(ivBytes
, sizeof(ivBytes
));
272 random
.generate(iv
, (uint32
)iv
.length());
274 /* Extract the key by wrapping it with the wrapping key. */
275 CssmClient::WrapKey
wrap(csp(), CSSM_ALGID_3DES_3KEY_EDE
);
276 wrap
.key(wrappingKey
);
277 wrap
.cred(getCredentials(CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED
, kSecCredentialTypeDefault
));
278 wrap
.mode(CSSM_ALGMODE_ECBPad
);
279 wrap
.padding(CSSM_PADDING_PKCS7
);
281 CssmClient::Key
wrappedKey(wrap(mKey
));
283 /* Unwrap the new key into the new Keychain. */
284 CssmClient::UnwrapKey
unwrap(keychain
->csp(), CSSM_ALGID_3DES_3KEY_EDE
);
285 unwrap
.key(wrappingKey
);
286 unwrap
.mode(CSSM_ALGMODE_ECBPad
);
287 unwrap
.padding(CSSM_PADDING_PKCS7
);
288 unwrap
.initVector(iv
);
290 /* Setup the dldbHandle in the context. */
291 unwrap
.add(CSSM_ATTRIBUTE_DL_DB_HANDLE
, ssDb
->handle());
293 /* Set up an initial aclEntry so we can change it after the unwrap. */
294 Access::Maker
maker(Allocator::standard(), Access::Maker::kAnyMakerType
);
295 ResourceControlContext rcc
;
296 maker
.initialOwner(rcc
, NULL
);
297 unwrap
.owner(rcc
.input());
299 /* Unwrap the key. */
300 uint32 usage
= mKey
->usage();
301 /* Work around csp brokeness where it sets all usage bits in the Keyheader when CSSM_KEYUSE_ANY is set. */
302 if (usage
& CSSM_KEYUSE_ANY
)
303 usage
= CSSM_KEYUSE_ANY
;
305 CssmClient::Key
unwrappedKey(unwrap(wrappedKey
, KeySpec(usage
,
306 (mKey
->attributes() | CSSM_KEYATTR_PERMANENT
) & ~(CSSM_KEYATTR_ALWAYS_SENSITIVE
| CSSM_KEYATTR_NEVER_EXTRACTABLE
),
309 /* Look up unwrapped key in the DLDB. */
310 DbUniqueRecord uniqueId
;
311 SSDbCursor
dbCursor(ssDb
, 1);
312 dbCursor
->recordType(recordType());
313 dbCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, label
);
314 CssmClient::Key copiedKey
;
315 if (!dbCursor
->nextKey(NULL
, copiedKey
, uniqueId
))
316 MacOSError::throwMe(errSecItemNotFound
);
318 // Set the initial label, application label, and application tag (if provided)
320 DbAttributes newDbAttributes
;
321 SSDbCursor
otherDbCursor(ssDb
, 1);
322 otherDbCursor
->recordType(recordType());
323 bool checkForDuplicates
= false;
325 for (UInt32 index
=0; index
< attrList
->count
; index
++) {
326 SecKeychainAttribute attr
= attrList
->attr
[index
];
327 CssmData
attrData(attr
.data
, attr
.length
);
328 if (attr
.tag
== kSecKeyPrintName
) {
329 newDbAttributes
.add(kInfoKeyPrintName
, attrData
);
331 if (attr
.tag
== kSecKeyLabel
) {
332 newDbAttributes
.add(kInfoKeyLabel
, attrData
);
333 otherDbCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, attrData
);
334 checkForDuplicates
= true;
336 if (attr
.tag
== kSecKeyApplicationTag
) {
337 newDbAttributes
.add(kInfoKeyApplicationTag
, attrData
);
338 otherDbCursor
->add(CSSM_DB_EQUAL
, kInfoKeyApplicationTag
, attrData
);
339 checkForDuplicates
= true;
343 DbAttributes otherDbAttributes
;
344 DbUniqueRecord otherUniqueId
;
345 CssmClient::Key otherKey
;
348 if (checkForDuplicates
&& otherDbCursor
->nextKey(&otherDbAttributes
, otherKey
, otherUniqueId
))
349 MacOSError::throwMe(errSecDuplicateItem
);
351 uniqueId
->modify(recordType(), &newDbAttributes
, NULL
, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
);
355 // clean up after trying to insert a duplicate key
356 uniqueId
->deleteRecord ();
361 /* Set the acl and owner on the unwrapped key. */
362 access
->setAccess(*unwrappedKey
, maker
);
364 /* Return a keychain item which represents the new key. */
365 Item
item(keychain
->item(recordType(), uniqueId
));
367 KCEventNotifier::PostKeychainEvent(kSecAddEvent
, keychain
, item
);
378 KeyItem::add(Keychain
&keychain
)
380 MacOSError::throwMe(errSecUnimplemented
);
383 CssmClient::SSDbUniqueRecord
384 KeyItem::ssDbUniqueRecord()
386 DbUniqueRecordImpl
*impl
= &*dbUniqueRecord();
387 Security::CssmClient::SSDbUniqueRecordImpl
*simpl
= dynamic_cast<Security::CssmClient::SSDbUniqueRecordImpl
*>(impl
);
390 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
);
393 return CssmClient::SSDbUniqueRecord(simpl
);
401 CssmClient::SSDbUniqueRecord
uniqueId(ssDbUniqueRecord());
402 CssmDataContainer
dataBlob(uniqueId
->allocator());
403 uniqueId
->get(NULL
, &dataBlob
);
404 mKey
= CssmClient::Key(uniqueId
->database()->csp(), *reinterpret_cast<CssmKey
*>(dataBlob
.Data
));
417 const CSSM_X509_ALGORITHM_IDENTIFIER
&
418 KeyItem::algorithmIdentifier()
422 CSSM_KEY_TYPE algorithm
423 CSSM_KEY_PTR cssmKey
= (CSSM_KEY_PTR
)thisData
->Data
;
425 static void printKeyHeader(
426 const CSSM_KEYHEADER
&hdr
)
428 printf(" Algorithm : ");
429 switch(hdr
.AlgorithmId
) {
430 CSSM_X509_ALGORITHM_IDENTIFIER algID
;
432 CSSM_OID
*CL_algToOid(
433 CSSM_ALGORITHMS algId
)
434 typedef struct cssm_x509_algorithm_identifier
{
436 CSSM_DATA parameters
;
437 } CSSM_X509_ALGORITHM_IDENTIFIER
, *CSSM_X509_ALGORITHM_IDENTIFIER_PTR
;
444 * itemID, used to locate Extended Attributes, is the public key hash for keys.
446 const CssmData
&KeyItem::itemID()
448 if(mPubKeyHash
.length() == 0) {
450 * Fetch the attribute from disk.
452 UInt32 tag
= kSecKeyLabel
;
454 SecKeychainAttributeInfo attrInfo
= {1, &tag
, &format
};
455 SecKeychainAttributeList
*attrList
= NULL
;
456 getAttributesAndData(&attrInfo
, NULL
, &attrList
, NULL
, NULL
);
457 if((attrList
== NULL
) || (attrList
->count
!= 1)) {
458 MacOSError::throwMe(errSecNoSuchAttr
);
460 mPubKeyHash
.copy(attrList
->attr
->data
, attrList
->attr
->length
);
461 freeAttributesAndData(attrList
, NULL
);
468 KeyItem::strengthInBits(const CSSM_X509_ALGORITHM_IDENTIFIER
*algid
)
470 // @@@ Make a context with key based on algid and use that to get the effective keysize and not just the logical one.
471 CSSM_KEY_SIZE keySize
= {};
472 CSSM_RETURN rv
= CSSM_QueryKeySizeInBits (csp()->handle(),
479 return keySize
.LogicalKeySizeInBits
;
482 const AccessCredentials
*
483 KeyItem::getCredentials(
484 CSSM_ACL_AUTHORIZATION_TAG operation
,
485 SecCredentialType credentialType
)
487 // @@@ Fix this to actually examine the ACL for this key and consider operation and do the right thing.
488 //AutoAclEntryInfoList aclInfos;
489 //key()->getAcl(aclInfos);
491 bool smartcard
= keychain() != NULL
? (keychain()->database()->dl()->guid() == gGuidAppleSdCSPDL
) : false;
494 switch (credentialType
)
496 case kSecCredentialTypeDefault
:
497 return smartcard
?globals().smartcardItemCredentials():globals().itemCredentials();
498 case kSecCredentialTypeWithUI
:
499 return smartcard
?globals().smartcardItemCredentials():factory
.promptCred();
500 case kSecCredentialTypeNoUI
:
501 return factory
.nullCred();
503 MacOSError::throwMe(errSecParam
);
508 KeyItem::operator == (KeyItem
&other
)
513 return this == &other
;
516 // If keychains are different, then keys are different
517 Keychain otherKeychain
= other
.keychain();
518 return (mKeychain
&& otherKeychain
&& (*mKeychain
== *otherKeychain
));
524 CSSM_ALGORITHMS algorithm
,
525 uint32 keySizeInBits
,
526 CSSM_CC_HANDLE contextHandle
,
527 CSSM_KEYUSE publicKeyUsage
,
528 uint32 publicKeyAttr
,
529 CSSM_KEYUSE privateKeyUsage
,
530 uint32 privateKeyAttr
,
531 SecPointer
<Access
> initialAccess
,
532 SecPointer
<KeyItem
> &outPublicKey
,
533 SecPointer
<KeyItem
> &outPrivateKey
)
535 bool freeKeys
= false;
536 bool deleteContext
= false;
538 if (!(keychain
->database()->dl()->subserviceMask() & CSSM_SERVICE_CSP
))
539 MacOSError::throwMe(errSecInvalidKeychain
);
541 SSDbImpl
* impl
= dynamic_cast<SSDbImpl
*>(&(*keychain
->database()));
544 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
);
548 CssmClient::CSP
csp(keychain
->csp());
549 CssmClient::CSP
appleCsp(gGuidAppleCSP
);
551 // Generate a random label to use initially
552 CssmClient::Random
random(appleCsp
, CSSM_ALGID_APPLE_YARROW
);
553 uint8 labelBytes
[20];
554 CssmData
label(labelBytes
, sizeof(labelBytes
));
555 random
.generate(label
, (uint32
)label
.Length
);
557 // Create a Access::Maker for the initial owner of the private key.
558 ResourceControlContext rcc
;
559 memset(&rcc
, 0, sizeof(rcc
));
561 // @@@ 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.
562 maker
.initialOwner(rcc
);
563 // Create the cred we need to manipulate the keys until we actually set a new access control for them.
564 const AccessCredentials
*cred
= maker
.cred();
566 CSSM_KEY publicCssmKey
, privateCssmKey
;
567 memset(&publicCssmKey
, 0, sizeof(publicCssmKey
));
568 memset(&privateCssmKey
, 0, sizeof(privateCssmKey
));
570 CSSM_CC_HANDLE ccHandle
= 0;
572 Item publicKeyItem
, privateKeyItem
;
577 ccHandle
= contextHandle
;
580 status
= CSSM_CSP_CreateKeyGenContext(csp
->handle(), algorithm
, keySizeInBits
, NULL
, NULL
, NULL
, NULL
, NULL
, &ccHandle
);
582 CssmError::throwMe(status
);
583 deleteContext
= true;
586 CSSM_DL_DB_HANDLE dldbHandle
= ssDb
->handle();
587 CSSM_DL_DB_HANDLE_PTR dldbHandlePtr
= &dldbHandle
;
588 CSSM_CONTEXT_ATTRIBUTE contextAttributes
= { CSSM_ATTRIBUTE_DL_DB_HANDLE
, sizeof(dldbHandle
), { (char *)dldbHandlePtr
} };
589 status
= CSSM_UpdateContextAttributes(ccHandle
, 1, &contextAttributes
);
591 CssmError::throwMe(status
);
593 // Generate the keypair
594 status
= CSSM_GenerateKeyPair(ccHandle
, publicKeyUsage
, publicKeyAttr
, &label
, &publicCssmKey
, privateKeyUsage
, privateKeyAttr
, &label
, &rcc
, &privateCssmKey
);
596 CssmError::throwMe(status
);
599 // Find the keys we just generated in the DL to get SecKeyRef's to them
600 // so we can change the label to be the hash of the public key, and
601 // fix up other attributes.
603 // Look up public key in the DLDB.
604 DbAttributes pubDbAttributes
;
605 DbUniqueRecord pubUniqueId
;
606 SSDbCursor
dbPubCursor(ssDb
, 1);
607 dbPubCursor
->recordType(CSSM_DL_DB_RECORD_PUBLIC_KEY
);
608 dbPubCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, label
);
609 CssmClient::Key publicKey
;
610 if (!dbPubCursor
->nextKey(&pubDbAttributes
, publicKey
, pubUniqueId
))
611 MacOSError::throwMe(errSecItemNotFound
);
613 // Look up private key in the DLDB.
614 DbAttributes privDbAttributes
;
615 DbUniqueRecord privUniqueId
;
616 SSDbCursor
dbPrivCursor(ssDb
, 1);
617 dbPrivCursor
->recordType(CSSM_DL_DB_RECORD_PRIVATE_KEY
);
618 dbPrivCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, label
);
619 CssmClient::Key privateKey
;
620 if (!dbPrivCursor
->nextKey(&privDbAttributes
, privateKey
, privUniqueId
))
621 MacOSError::throwMe(errSecItemNotFound
);
623 // Convert reference public key to a raw key so we can use it
625 CssmClient::WrapKey
wrap(csp
, CSSM_ALGID_NONE
);
627 CssmClient::Key rawPubKey
= wrap(publicKey
);
629 // Calculate the hash of the public key using the appleCSP.
630 CssmClient::PassThrough
passThrough(appleCsp
);
634 /* Given a CSSM_KEY_PTR in any format, obtain the SHA-1 hash of the
635 * associated key blob.
636 * Key is specified in CSSM_CSP_CreatePassThroughContext.
637 * Hash is allocated bythe CSP, in the App's memory, and returned
639 passThrough
.key(rawPubKey
);
640 passThrough(CSSM_APPLECSP_KEYDIGEST
, NULL
, &outData
);
641 cssmData
= reinterpret_cast<CssmData
*>(outData
);
642 CssmData
&pubKeyHash
= *cssmData
;
644 auto_ptr
<string
>privDescription
;
645 auto_ptr
<string
>pubDescription
;
647 privDescription
.reset(new string(initialAccess
->promptDescription()));
648 pubDescription
.reset(new string(initialAccess
->promptDescription()));
651 /* this path taken if no promptDescription available, e.g., for complex ACLs */
652 privDescription
.reset(new string("Private key"));
653 pubDescription
.reset(new string("Public key"));
656 // Set the label of the public key to the public key hash.
657 // Set the PrintName of the public key to the description in the acl.
658 pubDbAttributes
.add(kInfoKeyLabel
, pubKeyHash
);
659 pubDbAttributes
.add(kInfoKeyPrintName
, *pubDescription
);
660 pubUniqueId
->modify(CSSM_DL_DB_RECORD_PUBLIC_KEY
, &pubDbAttributes
, NULL
, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
);
662 // Set the label of the private key to the public key hash.
663 // Set the PrintName of the private key to the description in the acl.
664 privDbAttributes
.add(kInfoKeyLabel
, pubKeyHash
);
665 privDbAttributes
.add(kInfoKeyPrintName
, *privDescription
);
666 privUniqueId
->modify(CSSM_DL_DB_RECORD_PRIVATE_KEY
, &privDbAttributes
, NULL
, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
);
668 // @@@ Not exception safe!
669 csp
.allocator().free(cssmData
->Data
);
670 csp
.allocator().free(cssmData
);
672 // Finally fix the acl and owner of the private key to the specified access control settings.
673 initialAccess
->setAccess(*privateKey
, maker
);
675 if(publicKeyAttr
& CSSM_KEYATTR_PUBLIC_KEY_ENCRYPT
) {
677 * Make the public key acl completely open.
678 * If the key was not encrypted, it already has a wide-open
679 * ACL (though that is a feature of securityd; it's not
680 * CDSA-specified behavior).
682 SecPointer
<Access
> pubKeyAccess(new Access());
683 pubKeyAccess
->setAccess(*publicKey
, maker
);
686 // Create keychain items which will represent the keys.
687 publicKeyItem
= keychain
->item(CSSM_DL_DB_RECORD_PUBLIC_KEY
, pubUniqueId
);
688 privateKeyItem
= keychain
->item(CSSM_DL_DB_RECORD_PRIVATE_KEY
, privUniqueId
);
690 KeyItem
* impl
= dynamic_cast<KeyItem
*>(&(*publicKeyItem
));
693 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
);
698 impl
= dynamic_cast<KeyItem
*>(&(*privateKeyItem
));
701 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
);
704 outPrivateKey
= impl
;
710 // Delete the keys if something goes wrong so we don't end up with inaccessible keys in the database.
711 CSSM_FreeKey(csp
->handle(), cred
, &publicCssmKey
, TRUE
);
712 CSSM_FreeKey(csp
->handle(), cred
, &privateCssmKey
, TRUE
);
716 CSSM_DeleteContext(ccHandle
);
723 CSSM_FreeKey(csp
->handle(), NULL
, &publicCssmKey
, FALSE
);
724 CSSM_FreeKey(csp
->handle(), NULL
, &privateCssmKey
, FALSE
);
728 CSSM_DeleteContext(ccHandle
);
730 if (keychain
&& publicKeyItem
&& privateKeyItem
)
732 keychain
->postEvent(kSecAddEvent
, publicKeyItem
);
733 keychain
->postEvent(kSecAddEvent
, privateKeyItem
);
740 const CSSM_KEY
&publicWrappedKey
,
741 const CSSM_KEY
&privateWrappedKey
,
742 SecPointer
<Access
> initialAccess
,
743 SecPointer
<KeyItem
> &outPublicKey
,
744 SecPointer
<KeyItem
> &outPrivateKey
)
746 bool freePublicKey
= false;
747 bool freePrivateKey
= false;
748 bool deleteContext
= false;
750 if (!(keychain
->database()->dl()->subserviceMask() & CSSM_SERVICE_CSP
))
751 MacOSError::throwMe(errSecInvalidKeychain
);
753 SSDbImpl
* impl
= dynamic_cast<SSDbImpl
*>(&(*keychain
->database()));
756 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
);
760 CssmClient::CSP
csp(keychain
->csp());
761 CssmClient::CSP
appleCsp(gGuidAppleCSP
);
763 // Create a Access::Maker for the initial owner of the private key.
764 ResourceControlContext rcc
;
765 memset(&rcc
, 0, sizeof(rcc
));
766 Access::Maker
maker(Allocator::standard(), Access::Maker::kAnyMakerType
);
767 // @@@ Potentially provide a credential argument which allows us to unwrap keys in the csp.
768 // Currently the CSP lets anyone do this, but we might restrict this in the future, e.g.
769 // a smartcard could require out of band pin entry before a key can be generated.
770 maker
.initialOwner(rcc
);
771 // Create the cred we need to manipulate the keys until we actually set a new access control for them.
772 const AccessCredentials
*cred
= maker
.cred();
774 CSSM_KEY publicCssmKey
, privateCssmKey
;
775 memset(&publicCssmKey
, 0, sizeof(publicCssmKey
));
776 memset(&privateCssmKey
, 0, sizeof(privateCssmKey
));
778 CSSM_CC_HANDLE ccHandle
= 0;
780 Item publicKeyItem
, privateKeyItem
;
785 // Calculate the hash of the public key using the appleCSP.
786 CssmClient::PassThrough
passThrough(appleCsp
);
790 /* Given a CSSM_KEY_PTR in any format, obtain the SHA-1 hash of the
791 * associated key blob.
792 * Key is specified in CSSM_CSP_CreatePassThroughContext.
793 * Hash is allocated bythe CSP, in the App's memory, and returned
795 passThrough
.key(&publicWrappedKey
);
796 passThrough(CSSM_APPLECSP_KEYDIGEST
, NULL
, &outData
);
797 cssmData
= reinterpret_cast<CssmData
*>(outData
);
798 CssmData
&pubKeyHash
= *cssmData
;
800 status
= CSSM_CSP_CreateSymmetricContext(csp
->handle(), publicWrappedKey
.KeyHeader
.WrapAlgorithmId
, CSSM_ALGMODE_NONE
, NULL
, NULL
, NULL
, CSSM_PADDING_NONE
, NULL
, &ccHandle
);
802 CssmError::throwMe(status
);
803 deleteContext
= true;
805 CSSM_DL_DB_HANDLE dldbHandle
= ssDb
->handle();
806 CSSM_DL_DB_HANDLE_PTR dldbHandlePtr
= &dldbHandle
;
807 CSSM_CONTEXT_ATTRIBUTE contextAttributes
= { CSSM_ATTRIBUTE_DL_DB_HANDLE
, sizeof(dldbHandle
), { (char *)dldbHandlePtr
} };
808 status
= CSSM_UpdateContextAttributes(ccHandle
, 1, &contextAttributes
);
810 CssmError::throwMe(status
);
812 // Unwrap the the keys
813 CSSM_DATA descriptiveData
= {0, NULL
};
815 status
= CSSM_UnwrapKey(
819 publicWrappedKey
.KeyHeader
.KeyUsage
,
820 publicWrappedKey
.KeyHeader
.KeyAttr
| CSSM_KEYATTR_PERMANENT
,
827 CssmError::throwMe(status
);
828 freePublicKey
= true;
830 if (descriptiveData
.Data
!= NULL
)
831 free (descriptiveData
.Data
);
833 status
= CSSM_UnwrapKey(
837 privateWrappedKey
.KeyHeader
.KeyUsage
,
838 privateWrappedKey
.KeyHeader
.KeyAttr
| CSSM_KEYATTR_PERMANENT
,
845 CssmError::throwMe(status
);
847 if (descriptiveData
.Data
!= NULL
)
848 free (descriptiveData
.Data
);
850 freePrivateKey
= true;
852 // Find the keys we just generated in the DL to get SecKeyRefs to them
853 // so we can change the label to be the hash of the public key, and
854 // fix up other attributes.
856 // Look up public key in the DLDB.
857 DbAttributes pubDbAttributes
;
858 DbUniqueRecord pubUniqueId
;
859 SSDbCursor
dbPubCursor(ssDb
, 1);
860 dbPubCursor
->recordType(CSSM_DL_DB_RECORD_PUBLIC_KEY
);
861 dbPubCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, pubKeyHash
);
862 CssmClient::Key publicKey
;
863 if (!dbPubCursor
->nextKey(&pubDbAttributes
, publicKey
, pubUniqueId
))
864 MacOSError::throwMe(errSecItemNotFound
);
866 // Look up private key in the DLDB.
867 DbAttributes privDbAttributes
;
868 DbUniqueRecord privUniqueId
;
869 SSDbCursor
dbPrivCursor(ssDb
, 1);
870 dbPrivCursor
->recordType(CSSM_DL_DB_RECORD_PRIVATE_KEY
);
871 dbPrivCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, pubKeyHash
);
872 CssmClient::Key privateKey
;
873 if (!dbPrivCursor
->nextKey(&privDbAttributes
, privateKey
, privUniqueId
))
874 MacOSError::throwMe(errSecItemNotFound
);
876 // @@@ Not exception safe!
877 csp
.allocator().free(cssmData
->Data
);
878 csp
.allocator().free(cssmData
);
880 auto_ptr
<string
>privDescription
;
881 auto_ptr
<string
>pubDescription
;
883 privDescription
.reset(new string(initialAccess
->promptDescription()));
884 pubDescription
.reset(new string(initialAccess
->promptDescription()));
887 /* this path taken if no promptDescription available, e.g., for complex ACLs */
888 privDescription
.reset(new string("Private key"));
889 pubDescription
.reset(new string("Public key"));
892 // Set the label of the public key to the public key hash.
893 // Set the PrintName of the public key to the description in the acl.
894 pubDbAttributes
.add(kInfoKeyPrintName
, *pubDescription
);
895 pubUniqueId
->modify(CSSM_DL_DB_RECORD_PUBLIC_KEY
, &pubDbAttributes
, NULL
, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
);
897 // Set the label of the private key to the public key hash.
898 // Set the PrintName of the private key to the description in the acl.
899 privDbAttributes
.add(kInfoKeyPrintName
, *privDescription
);
900 privUniqueId
->modify(CSSM_DL_DB_RECORD_PRIVATE_KEY
, &privDbAttributes
, NULL
, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
);
902 // Finally fix the acl and owner of the private key to the specified access control settings.
903 initialAccess
->setAccess(*privateKey
, maker
);
905 // Make the public key acl completely open
906 SecPointer
<Access
> pubKeyAccess(new Access());
907 pubKeyAccess
->setAccess(*publicKey
, maker
);
909 // Create keychain items which will represent the keys.
910 publicKeyItem
= keychain
->item(CSSM_DL_DB_RECORD_PUBLIC_KEY
, pubUniqueId
);
911 privateKeyItem
= keychain
->item(CSSM_DL_DB_RECORD_PRIVATE_KEY
, privUniqueId
);
913 KeyItem
* impl
= dynamic_cast<KeyItem
*>(&(*publicKeyItem
));
916 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
);
921 impl
= dynamic_cast<KeyItem
*>(&(*privateKeyItem
));
924 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
);
926 outPrivateKey
= impl
;
931 CSSM_FreeKey(csp
->handle(), cred
, &publicCssmKey
, TRUE
);
933 CSSM_FreeKey(csp
->handle(), cred
, &privateCssmKey
, TRUE
);
936 CSSM_DeleteContext(ccHandle
);
942 CSSM_FreeKey(csp
->handle(), cred
, &publicCssmKey
, FALSE
);
944 CSSM_FreeKey(csp
->handle(), cred
, &privateCssmKey
, FALSE
);
947 CSSM_DeleteContext(ccHandle
);
949 if (keychain
&& publicKeyItem
&& privateKeyItem
)
951 KCEventNotifier::PostKeychainEvent(kSecAddEvent
, keychain
, publicKeyItem
);
952 KCEventNotifier::PostKeychainEvent(kSecAddEvent
, keychain
, privateKeyItem
);
957 KeyItem::generateWithAttributes(const SecKeychainAttributeList
*attrList
,
959 CSSM_ALGORITHMS algorithm
,
960 uint32 keySizeInBits
,
961 CSSM_CC_HANDLE contextHandle
,
962 CSSM_KEYUSE keyUsage
,
964 SecPointer
<Access
> initialAccess
)
966 CssmClient::CSP
appleCsp(gGuidAppleCSP
);
967 CssmClient::CSP
csp(NULL
);
969 uint8 labelBytes
[20];
970 CssmData
label(labelBytes
, sizeof(labelBytes
));
971 bool freeKey
= false;
972 bool deleteContext
= false;
973 const CSSM_DATA
*plabel
= NULL
;
977 if (!(keychain
->database()->dl()->subserviceMask() & CSSM_SERVICE_CSP
))
978 MacOSError::throwMe(errSecInvalidKeychain
);
980 SSDbImpl
* impl
= dynamic_cast<SSDbImpl
*>(&(*keychain
->database()));
983 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
);
987 csp
= keychain
->csp();
989 // Generate a random label to use initially
990 CssmClient::Random
random(appleCsp
, CSSM_ALGID_APPLE_YARROW
);
991 random
.generate(label
, (uint32
)label
.Length
);
996 // Not a persistent key so create it in the regular csp
1000 // Create a Access::Maker for the initial owner of the private key.
1001 ResourceControlContext
*prcc
= NULL
, rcc
;
1002 const AccessCredentials
*cred
= NULL
;
1003 Access::Maker maker
;
1004 if (keychain
&& initialAccess
)
1006 memset(&rcc
, 0, sizeof(rcc
));
1007 // @@@ Potentially provide a credential argument which allows us to generate keys in the csp.
1008 // Currently the CSP lets anyone do this, but we might restrict this in the future, e.g. a smartcard
1009 // could require out-of-band pin entry before a key can be generated.
1010 maker
.initialOwner(rcc
);
1011 // Create the cred we need to manipulate the keys until we actually set a new access control for them.
1012 cred
= maker
.cred();
1018 CSSM_CC_HANDLE ccHandle
= 0;
1025 ccHandle
= contextHandle
;
1028 status
= CSSM_CSP_CreateKeyGenContext(csp
->handle(), algorithm
, keySizeInBits
, NULL
, NULL
, NULL
, NULL
, NULL
, &ccHandle
);
1030 CssmError::throwMe(status
);
1031 deleteContext
= true;
1036 CSSM_DL_DB_HANDLE dldbHandle
= ssDb
->handle();
1037 CSSM_DL_DB_HANDLE_PTR dldbHandlePtr
= &dldbHandle
;
1038 CSSM_CONTEXT_ATTRIBUTE contextAttributes
= { CSSM_ATTRIBUTE_DL_DB_HANDLE
, sizeof(dldbHandle
), { (char *)dldbHandlePtr
} };
1039 status
= CSSM_UpdateContextAttributes(ccHandle
, 1, &contextAttributes
);
1041 CssmError::throwMe(status
);
1043 keyAttr
|= CSSM_KEYATTR_PERMANENT
;
1047 status
= CSSM_GenerateKey(ccHandle
, keyUsage
, keyAttr
, plabel
, prcc
, &cssmKey
);
1049 CssmError::throwMe(status
);
1054 // Find the key we just generated in the DL and get a SecKeyRef
1055 // so we can specify the label attribute(s) and initial ACL.
1057 // Look up key in the DLDB.
1058 DbAttributes dbAttributes
;
1059 DbUniqueRecord uniqueId
;
1060 SSDbCursor
dbCursor(ssDb
, 1);
1061 dbCursor
->recordType(CSSM_DL_DB_RECORD_SYMMETRIC_KEY
);
1062 dbCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, label
);
1063 CssmClient::Key key
;
1064 if (!dbCursor
->nextKey(&dbAttributes
, key
, uniqueId
))
1065 MacOSError::throwMe(errSecItemNotFound
);
1067 // Set the initial label, application label, and application tag (if provided)
1069 DbAttributes newDbAttributes
;
1070 SSDbCursor
otherDbCursor(ssDb
, 1);
1071 otherDbCursor
->recordType(CSSM_DL_DB_RECORD_SYMMETRIC_KEY
);
1072 bool checkForDuplicates
= false;
1074 for (UInt32 index
=0; index
< attrList
->count
; index
++) {
1075 SecKeychainAttribute attr
= attrList
->attr
[index
];
1076 CssmData
attrData(attr
.data
, attr
.length
);
1077 if (attr
.tag
== kSecKeyPrintName
) {
1078 newDbAttributes
.add(kInfoKeyPrintName
, attrData
);
1080 if (attr
.tag
== kSecKeyLabel
) {
1081 newDbAttributes
.add(kInfoKeyLabel
, attrData
);
1082 otherDbCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, attrData
);
1083 checkForDuplicates
= true;
1085 if (attr
.tag
== kSecKeyApplicationTag
) {
1086 newDbAttributes
.add(kInfoKeyApplicationTag
, attrData
);
1087 otherDbCursor
->add(CSSM_DB_EQUAL
, kInfoKeyApplicationTag
, attrData
);
1088 checkForDuplicates
= true;
1092 DbAttributes otherDbAttributes
;
1093 DbUniqueRecord otherUniqueId
;
1094 CssmClient::Key otherKey
;
1095 if (checkForDuplicates
&& otherDbCursor
->nextKey(&otherDbAttributes
, otherKey
, otherUniqueId
))
1096 MacOSError::throwMe(errSecDuplicateItem
);
1098 uniqueId
->modify(CSSM_DL_DB_RECORD_SYMMETRIC_KEY
, &newDbAttributes
, NULL
, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
);
1101 // Finally, fix the acl and owner of the key to the specified access control settings.
1103 initialAccess
->setAccess(*key
, maker
);
1105 // Create keychain item which will represent the key.
1106 keyItem
= keychain
->item(CSSM_DL_DB_RECORD_SYMMETRIC_KEY
, uniqueId
);
1110 CssmClient::Key
tempKey(csp
, cssmKey
);
1111 keyItem
= new KeyItem(tempKey
);
1118 // Delete the key if something goes wrong so we don't end up with inaccessible keys in the database.
1119 CSSM_FreeKey(csp
->handle(), cred
, &cssmKey
, TRUE
);
1123 CSSM_DeleteContext(ccHandle
);
1130 CSSM_FreeKey(csp
->handle(), NULL
, &cssmKey
, FALSE
);
1134 CSSM_DeleteContext(ccHandle
);
1136 if (keychain
&& keyItem
)
1137 keychain
->postEvent(kSecAddEvent
, keyItem
);
1139 KeyItem
* item
= dynamic_cast<KeyItem
*>(&*keyItem
);
1142 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
);
1149 KeyItem::generate(Keychain keychain
,
1150 CSSM_ALGORITHMS algorithm
,
1151 uint32 keySizeInBits
,
1152 CSSM_CC_HANDLE contextHandle
,
1153 CSSM_KEYUSE keyUsage
,
1155 SecPointer
<Access
> initialAccess
)
1157 return KeyItem::generateWithAttributes(NULL
, keychain
,
1158 algorithm
, keySizeInBits
, contextHandle
,
1159 keyUsage
, keyAttr
, initialAccess
);
1163 void KeyItem::RawSign(SecPadding padding
, CSSM_DATA dataToSign
, const AccessCredentials
*credentials
, CSSM_DATA
& signature
)
1165 CSSM_ALGORITHMS baseAlg
= key()->header().algorithm();
1167 if ((baseAlg
!= CSSM_ALGID_RSA
) && (baseAlg
!= CSSM_ALGID_ECDSA
))
1169 MacOSError::throwMe(errSecParam
);
1172 CSSM_ALGORITHMS paddingAlg
= CSSM_PADDING_PKCS1
;
1176 case kSecPaddingPKCS1
:
1178 paddingAlg
= CSSM_PADDING_PKCS1
;
1182 case kSecPaddingPKCS1MD2
:
1184 baseAlg
= CSSM_ALGID_MD2WithRSA
;
1188 case kSecPaddingPKCS1MD5
:
1190 baseAlg
= CSSM_ALGID_MD5WithRSA
;
1194 case kSecPaddingPKCS1SHA1
:
1196 baseAlg
= CSSM_ALGID_SHA1WithRSA
;
1202 paddingAlg
= CSSM_PADDING_NONE
;
1207 Sign
signContext(csp(), baseAlg
);
1208 signContext
.key(key());
1209 signContext
.set(CSSM_ATTRIBUTE_PADDING
, paddingAlg
);
1210 signContext
.cred(credentials
);
1212 CssmData
data(dataToSign
.Data
, dataToSign
.Length
);
1213 signContext
.sign(data
);
1215 CssmData
sig(signature
.Data
, signature
.Length
);
1216 signContext(sig
); // yes, this is an accessor. Believe it, or not.
1217 signature
.Length
= sig
.length();
1222 void KeyItem::RawVerify(SecPadding padding
, CSSM_DATA dataToVerify
, const AccessCredentials
*credentials
, CSSM_DATA sig
)
1224 CSSM_ALGORITHMS baseAlg
= key()->header().algorithm();
1225 if ((baseAlg
!= CSSM_ALGID_RSA
) && (baseAlg
!= CSSM_ALGID_ECDSA
))
1227 MacOSError::throwMe(errSecParam
);
1230 CSSM_ALGORITHMS paddingAlg
= CSSM_PADDING_PKCS1
;
1234 case kSecPaddingPKCS1
:
1236 paddingAlg
= CSSM_PADDING_PKCS1
;
1240 case kSecPaddingPKCS1MD2
:
1242 baseAlg
= CSSM_ALGID_MD2WithRSA
;
1246 case kSecPaddingPKCS1MD5
:
1248 baseAlg
= CSSM_ALGID_MD5WithRSA
;
1252 case kSecPaddingPKCS1SHA1
:
1254 baseAlg
= CSSM_ALGID_SHA1WithRSA
;
1260 paddingAlg
= CSSM_PADDING_NONE
;
1265 Verify
verifyContext(csp(), baseAlg
);
1266 verifyContext
.key(key());
1267 verifyContext
.set(CSSM_ATTRIBUTE_PADDING
, paddingAlg
);
1268 verifyContext
.cred(credentials
);
1270 CssmData
data(dataToVerify
.Data
, dataToVerify
.Length
);
1271 CssmData
signature(sig
.Data
, sig
.Length
);
1272 verifyContext
.verify(data
, signature
);
1277 void KeyItem::Encrypt(SecPadding padding
, CSSM_DATA dataToEncrypt
, const AccessCredentials
*credentials
, CSSM_DATA
& encryptedData
)
1279 CSSM_ALGORITHMS baseAlg
= key()->header().algorithm();
1280 if (baseAlg
!= CSSM_ALGID_RSA
)
1282 MacOSError::throwMe(errSecParam
);
1285 CSSM_ALGORITHMS paddingAlg
= CSSM_PADDING_PKCS1
;
1289 case kSecPaddingPKCS1
:
1291 paddingAlg
= CSSM_PADDING_PKCS1
;
1297 paddingAlg
= CSSM_PADDING_NONE
;
1302 CssmClient::Encrypt
encryptContext(csp(), baseAlg
);
1303 encryptContext
.key(key());
1304 encryptContext
.padding(paddingAlg
);
1305 encryptContext
.cred(credentials
);
1307 CssmData
inData(dataToEncrypt
.Data
, dataToEncrypt
.Length
);
1308 CssmData
outData(encryptedData
.Data
, encryptedData
.Length
);
1309 CssmData
remData((void*) NULL
, 0);
1311 encryptedData
.Length
= encryptContext
.encrypt(inData
, outData
, remData
);
1316 void KeyItem::Decrypt(SecPadding padding
, CSSM_DATA dataToDecrypt
, const AccessCredentials
*credentials
, CSSM_DATA
& decryptedData
)
1318 CSSM_ALGORITHMS baseAlg
= key()->header().algorithm();
1319 if (baseAlg
!= CSSM_ALGID_RSA
)
1321 MacOSError::throwMe(errSecParam
);
1324 CSSM_ALGORITHMS paddingAlg
= CSSM_PADDING_PKCS1
;
1328 case kSecPaddingPKCS1
:
1330 paddingAlg
= CSSM_PADDING_PKCS1
;
1337 paddingAlg
= CSSM_PADDING_NONE
;
1342 CssmClient::Decrypt
decryptContext(csp(), baseAlg
);
1343 decryptContext
.key(key());
1344 decryptContext
.padding(paddingAlg
);
1345 decryptContext
.cred(credentials
);
1347 CssmData
inData(dataToDecrypt
.Data
, dataToDecrypt
.Length
);
1348 CssmData
outData(decryptedData
.Data
, decryptedData
.Length
);
1349 CssmData
remData((void*) NULL
, 0);
1350 decryptedData
.Length
= decryptContext
.decrypt(inData
, outData
, remData
);
1351 if (remData
.Data
!= NULL
)
1357 CFHashCode
KeyItem::hash()
1359 CFHashCode result
= 0;
1360 const CSSM_KEY
*cssmKey
= key();
1361 if (NULL
!= cssmKey
)
1363 unsigned char digest
[CC_SHA256_DIGEST_LENGTH
];
1365 CFIndex size_of_data
= sizeof(CSSM_KEYHEADER
) + cssmKey
->KeyData
.Length
;
1367 CFMutableDataRef temp_cfdata
= CFDataCreateMutable(kCFAllocatorDefault
, size_of_data
);
1368 if (NULL
== temp_cfdata
)
1373 CFDataAppendBytes(temp_cfdata
, (const UInt8
*)cssmKey
, sizeof(CSSM_KEYHEADER
));
1374 CFDataAppendBytes(temp_cfdata
, cssmKey
->KeyData
.Data
, cssmKey
->KeyData
.Length
);
1376 if (size_of_data
< 80)
1378 // If it is less than 80 bytes then CFData can be used
1379 result
= CFHash(temp_cfdata
);
1380 CFRelease(temp_cfdata
);
1382 // CFData truncates its hash value to 80 bytes. ????
1383 // In order to do the 'right thing' a SHA 256 hash will be used to
1384 // include all of the data
1387 memset(digest
, 0, CC_SHA256_DIGEST_LENGTH
);
1389 CC_SHA256((const void *)CFDataGetBytePtr(temp_cfdata
), (CC_LONG
)CFDataGetLength(temp_cfdata
), digest
);
1391 CFDataRef data_to_hash
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
,
1392 (const UInt8
*)digest
, CC_SHA256_DIGEST_LENGTH
, kCFAllocatorNull
);
1393 result
= CFHash(data_to_hash
);
1394 CFRelease(data_to_hash
);
1395 CFRelease(temp_cfdata
);