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
);
404 CssmClient::SSDbUniqueRecord
uniqueId(ssDbUniqueRecord());
405 CssmDataContainer
dataBlob(uniqueId
->allocator());
406 uniqueId
->get(NULL
, &dataBlob
);
407 mKey
= CssmClient::Key(uniqueId
->database()->csp(), *reinterpret_cast<CssmKey
*>(dataBlob
.Data
));
420 const CSSM_X509_ALGORITHM_IDENTIFIER
&
421 KeyItem::algorithmIdentifier()
425 CSSM_KEY_TYPE algorithm
426 CSSM_KEY_PTR cssmKey
= (CSSM_KEY_PTR
)thisData
->Data
;
428 static void printKeyHeader(
429 const CSSM_KEYHEADER
&hdr
)
431 printf(" Algorithm : ");
432 switch(hdr
.AlgorithmId
) {
433 CSSM_X509_ALGORITHM_IDENTIFIER algID
;
435 CSSM_OID
*CL_algToOid(
436 CSSM_ALGORITHMS algId
)
437 typedef struct cssm_x509_algorithm_identifier
{
439 CSSM_DATA parameters
;
440 } CSSM_X509_ALGORITHM_IDENTIFIER
, *CSSM_X509_ALGORITHM_IDENTIFIER_PTR
;
447 * itemID, used to locate Extended Attributes, is the public key hash for keys.
449 const CssmData
&KeyItem::itemID()
451 if(mPubKeyHash
.length() == 0) {
453 * Fetch the attribute from disk.
455 UInt32 tag
= kSecKeyLabel
;
457 SecKeychainAttributeInfo attrInfo
= {1, &tag
, &format
};
458 SecKeychainAttributeList
*attrList
= NULL
;
459 getAttributesAndData(&attrInfo
, NULL
, &attrList
, NULL
, NULL
);
460 if((attrList
== NULL
) || (attrList
->count
!= 1)) {
461 MacOSError::throwMe(errSecNoSuchAttr
);
463 mPubKeyHash
.copy(attrList
->attr
->data
, attrList
->attr
->length
);
464 freeAttributesAndData(attrList
, NULL
);
471 KeyItem::strengthInBits(const CSSM_X509_ALGORITHM_IDENTIFIER
*algid
)
473 // @@@ Make a context with key based on algid and use that to get the effective keysize and not just the logical one.
474 CSSM_KEY_SIZE keySize
= {};
475 CSSM_RETURN rv
= CSSM_QueryKeySizeInBits (csp()->handle(),
482 return keySize
.LogicalKeySizeInBits
;
485 const AccessCredentials
*
486 KeyItem::getCredentials(
487 CSSM_ACL_AUTHORIZATION_TAG operation
,
488 SecCredentialType credentialType
)
490 // @@@ Fix this to actually examine the ACL for this key and consider operation and do the right thing.
491 //AutoAclEntryInfoList aclInfos;
492 //key()->getAcl(aclInfos);
494 bool smartcard
= keychain() != NULL
? (keychain()->database()->dl()->guid() == gGuidAppleSdCSPDL
) : false;
497 switch (credentialType
)
499 case kSecCredentialTypeDefault
:
500 return smartcard
?globals().smartcardItemCredentials():globals().itemCredentials();
501 case kSecCredentialTypeWithUI
:
502 return smartcard
?globals().smartcardItemCredentials():factory
.promptCred();
503 case kSecCredentialTypeNoUI
:
504 return factory
.nullCred();
506 MacOSError::throwMe(errSecParam
);
511 KeyItem::operator == (KeyItem
&other
)
516 return this == &other
;
519 // If keychains are different, then keys are different
520 Keychain otherKeychain
= other
.keychain();
521 return (mKeychain
&& otherKeychain
&& (*mKeychain
== *otherKeychain
));
527 CSSM_ALGORITHMS algorithm
,
528 uint32 keySizeInBits
,
529 CSSM_CC_HANDLE contextHandle
,
530 CSSM_KEYUSE publicKeyUsage
,
531 uint32 publicKeyAttr
,
532 CSSM_KEYUSE privateKeyUsage
,
533 uint32 privateKeyAttr
,
534 SecPointer
<Access
> initialAccess
,
535 SecPointer
<KeyItem
> &outPublicKey
,
536 SecPointer
<KeyItem
> &outPrivateKey
)
538 bool freeKeys
= false;
539 bool deleteContext
= false;
541 if (!(keychain
->database()->dl()->subserviceMask() & CSSM_SERVICE_CSP
))
542 MacOSError::throwMe(errSecInvalidKeychain
);
544 SSDbImpl
* impl
= dynamic_cast<SSDbImpl
*>(&(*keychain
->database()));
547 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
);
551 CssmClient::CSP
csp(keychain
->csp());
552 CssmClient::CSP
appleCsp(gGuidAppleCSP
);
554 // Generate a random label to use initially
555 CssmClient::Random
random(appleCsp
, CSSM_ALGID_APPLE_YARROW
);
556 uint8 labelBytes
[20];
557 CssmData
label(labelBytes
, sizeof(labelBytes
));
558 random
.generate(label
, (uint32
)label
.Length
);
560 // Create a Access::Maker for the initial owner of the private key.
561 ResourceControlContext rcc
;
562 memset(&rcc
, 0, sizeof(rcc
));
564 // @@@ 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.
565 maker
.initialOwner(rcc
);
566 // Create the cred we need to manipulate the keys until we actually set a new access control for them.
567 const AccessCredentials
*cred
= maker
.cred();
569 CSSM_KEY publicCssmKey
, privateCssmKey
;
570 memset(&publicCssmKey
, 0, sizeof(publicCssmKey
));
571 memset(&privateCssmKey
, 0, sizeof(privateCssmKey
));
573 CSSM_CC_HANDLE ccHandle
= 0;
575 Item publicKeyItem
, privateKeyItem
;
580 ccHandle
= contextHandle
;
583 status
= CSSM_CSP_CreateKeyGenContext(csp
->handle(), algorithm
, keySizeInBits
, NULL
, NULL
, NULL
, NULL
, NULL
, &ccHandle
);
585 CssmError::throwMe(status
);
586 deleteContext
= true;
589 CSSM_DL_DB_HANDLE dldbHandle
= ssDb
->handle();
590 CSSM_DL_DB_HANDLE_PTR dldbHandlePtr
= &dldbHandle
;
591 CSSM_CONTEXT_ATTRIBUTE contextAttributes
= { CSSM_ATTRIBUTE_DL_DB_HANDLE
, sizeof(dldbHandle
), { (char *)dldbHandlePtr
} };
592 status
= CSSM_UpdateContextAttributes(ccHandle
, 1, &contextAttributes
);
594 CssmError::throwMe(status
);
596 // Generate the keypair
597 status
= CSSM_GenerateKeyPair(ccHandle
, publicKeyUsage
, publicKeyAttr
, &label
, &publicCssmKey
, privateKeyUsage
, privateKeyAttr
, &label
, &rcc
, &privateCssmKey
);
599 CssmError::throwMe(status
);
602 // Find the keys we just generated in the DL to get SecKeyRef's to them
603 // so we can change the label to be the hash of the public key, and
604 // fix up other attributes.
606 // Look up public key in the DLDB.
607 DbAttributes pubDbAttributes
;
608 DbUniqueRecord pubUniqueId
;
609 SSDbCursor
dbPubCursor(ssDb
, 1);
610 dbPubCursor
->recordType(CSSM_DL_DB_RECORD_PUBLIC_KEY
);
611 dbPubCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, label
);
612 CssmClient::Key publicKey
;
613 if (!dbPubCursor
->nextKey(&pubDbAttributes
, publicKey
, pubUniqueId
))
614 MacOSError::throwMe(errSecItemNotFound
);
616 // Look up private key in the DLDB.
617 DbAttributes privDbAttributes
;
618 DbUniqueRecord privUniqueId
;
619 SSDbCursor
dbPrivCursor(ssDb
, 1);
620 dbPrivCursor
->recordType(CSSM_DL_DB_RECORD_PRIVATE_KEY
);
621 dbPrivCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, label
);
622 CssmClient::Key privateKey
;
623 if (!dbPrivCursor
->nextKey(&privDbAttributes
, privateKey
, privUniqueId
))
624 MacOSError::throwMe(errSecItemNotFound
);
626 // Convert reference public key to a raw key so we can use it
628 CssmClient::WrapKey
wrap(csp
, CSSM_ALGID_NONE
);
630 CssmClient::Key rawPubKey
= wrap(publicKey
);
632 // Calculate the hash of the public key using the appleCSP.
633 CssmClient::PassThrough
passThrough(appleCsp
);
637 /* Given a CSSM_KEY_PTR in any format, obtain the SHA-1 hash of the
638 * associated key blob.
639 * Key is specified in CSSM_CSP_CreatePassThroughContext.
640 * Hash is allocated bythe CSP, in the App's memory, and returned
642 passThrough
.key(rawPubKey
);
643 passThrough(CSSM_APPLECSP_KEYDIGEST
, NULL
, &outData
);
644 cssmData
= reinterpret_cast<CssmData
*>(outData
);
645 CssmData
&pubKeyHash
= *cssmData
;
647 auto_ptr
<string
>privDescription
;
648 auto_ptr
<string
>pubDescription
;
650 privDescription
.reset(new string(initialAccess
->promptDescription()));
651 pubDescription
.reset(new string(initialAccess
->promptDescription()));
654 /* this path taken if no promptDescription available, e.g., for complex ACLs */
655 privDescription
.reset(new string("Private key"));
656 pubDescription
.reset(new string("Public key"));
659 // Set the label of the public key to the public key hash.
660 // Set the PrintName of the public key to the description in the acl.
661 pubDbAttributes
.add(kInfoKeyLabel
, pubKeyHash
);
662 pubDbAttributes
.add(kInfoKeyPrintName
, *pubDescription
);
663 pubUniqueId
->modify(CSSM_DL_DB_RECORD_PUBLIC_KEY
, &pubDbAttributes
, NULL
, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
);
665 // Set the label of the private key to the public key hash.
666 // Set the PrintName of the private key to the description in the acl.
667 privDbAttributes
.add(kInfoKeyLabel
, pubKeyHash
);
668 privDbAttributes
.add(kInfoKeyPrintName
, *privDescription
);
669 privUniqueId
->modify(CSSM_DL_DB_RECORD_PRIVATE_KEY
, &privDbAttributes
, NULL
, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
);
671 // @@@ Not exception safe!
672 csp
.allocator().free(cssmData
->Data
);
673 csp
.allocator().free(cssmData
);
675 // Finally fix the acl and owner of the private key to the specified access control settings.
676 initialAccess
->setAccess(*privateKey
, maker
);
678 if(publicKeyAttr
& CSSM_KEYATTR_PUBLIC_KEY_ENCRYPT
) {
680 * Make the public key acl completely open.
681 * If the key was not encrypted, it already has a wide-open
682 * ACL (though that is a feature of securityd; it's not
683 * CDSA-specified behavior).
685 SecPointer
<Access
> pubKeyAccess(new Access());
686 pubKeyAccess
->setAccess(*publicKey
, maker
);
689 // Create keychain items which will represent the keys.
690 publicKeyItem
= keychain
->item(CSSM_DL_DB_RECORD_PUBLIC_KEY
, pubUniqueId
);
691 privateKeyItem
= keychain
->item(CSSM_DL_DB_RECORD_PRIVATE_KEY
, privUniqueId
);
693 KeyItem
* impl
= dynamic_cast<KeyItem
*>(&(*publicKeyItem
));
696 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
);
701 impl
= dynamic_cast<KeyItem
*>(&(*privateKeyItem
));
704 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
);
707 outPrivateKey
= impl
;
713 // Delete the keys if something goes wrong so we don't end up with inaccessible keys in the database.
714 CSSM_FreeKey(csp
->handle(), cred
, &publicCssmKey
, TRUE
);
715 CSSM_FreeKey(csp
->handle(), cred
, &privateCssmKey
, TRUE
);
719 CSSM_DeleteContext(ccHandle
);
726 CSSM_FreeKey(csp
->handle(), NULL
, &publicCssmKey
, FALSE
);
727 CSSM_FreeKey(csp
->handle(), NULL
, &privateCssmKey
, FALSE
);
731 CSSM_DeleteContext(ccHandle
);
733 if (keychain
&& publicKeyItem
&& privateKeyItem
)
735 keychain
->postEvent(kSecAddEvent
, publicKeyItem
);
736 keychain
->postEvent(kSecAddEvent
, privateKeyItem
);
743 const CSSM_KEY
&publicWrappedKey
,
744 const CSSM_KEY
&privateWrappedKey
,
745 SecPointer
<Access
> initialAccess
,
746 SecPointer
<KeyItem
> &outPublicKey
,
747 SecPointer
<KeyItem
> &outPrivateKey
)
749 bool freePublicKey
= false;
750 bool freePrivateKey
= false;
751 bool deleteContext
= false;
753 if (!(keychain
->database()->dl()->subserviceMask() & CSSM_SERVICE_CSP
))
754 MacOSError::throwMe(errSecInvalidKeychain
);
756 SSDbImpl
* impl
= dynamic_cast<SSDbImpl
*>(&(*keychain
->database()));
759 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
);
763 CssmClient::CSP
csp(keychain
->csp());
764 CssmClient::CSP
appleCsp(gGuidAppleCSP
);
766 // Create a Access::Maker for the initial owner of the private key.
767 ResourceControlContext rcc
;
768 memset(&rcc
, 0, sizeof(rcc
));
769 Access::Maker
maker(Allocator::standard(), Access::Maker::kAnyMakerType
);
770 // @@@ Potentially provide a credential argument which allows us to unwrap keys in the csp.
771 // Currently the CSP lets anyone do this, but we might restrict this in the future, e.g.
772 // a smartcard could require out of band pin entry before a key can be generated.
773 maker
.initialOwner(rcc
);
774 // Create the cred we need to manipulate the keys until we actually set a new access control for them.
775 const AccessCredentials
*cred
= maker
.cred();
777 CSSM_KEY publicCssmKey
, privateCssmKey
;
778 memset(&publicCssmKey
, 0, sizeof(publicCssmKey
));
779 memset(&privateCssmKey
, 0, sizeof(privateCssmKey
));
781 CSSM_CC_HANDLE ccHandle
= 0;
783 Item publicKeyItem
, privateKeyItem
;
788 // Calculate the hash of the public key using the appleCSP.
789 CssmClient::PassThrough
passThrough(appleCsp
);
793 /* Given a CSSM_KEY_PTR in any format, obtain the SHA-1 hash of the
794 * associated key blob.
795 * Key is specified in CSSM_CSP_CreatePassThroughContext.
796 * Hash is allocated bythe CSP, in the App's memory, and returned
798 passThrough
.key(&publicWrappedKey
);
799 passThrough(CSSM_APPLECSP_KEYDIGEST
, NULL
, &outData
);
800 cssmData
= reinterpret_cast<CssmData
*>(outData
);
801 CssmData
&pubKeyHash
= *cssmData
;
803 status
= CSSM_CSP_CreateSymmetricContext(csp
->handle(), publicWrappedKey
.KeyHeader
.WrapAlgorithmId
, CSSM_ALGMODE_NONE
, NULL
, NULL
, NULL
, CSSM_PADDING_NONE
, NULL
, &ccHandle
);
805 CssmError::throwMe(status
);
806 deleteContext
= true;
808 CSSM_DL_DB_HANDLE dldbHandle
= ssDb
->handle();
809 CSSM_DL_DB_HANDLE_PTR dldbHandlePtr
= &dldbHandle
;
810 CSSM_CONTEXT_ATTRIBUTE contextAttributes
= { CSSM_ATTRIBUTE_DL_DB_HANDLE
, sizeof(dldbHandle
), { (char *)dldbHandlePtr
} };
811 status
= CSSM_UpdateContextAttributes(ccHandle
, 1, &contextAttributes
);
813 CssmError::throwMe(status
);
815 // Unwrap the the keys
816 CSSM_DATA descriptiveData
= {0, NULL
};
818 status
= CSSM_UnwrapKey(
822 publicWrappedKey
.KeyHeader
.KeyUsage
,
823 publicWrappedKey
.KeyHeader
.KeyAttr
| CSSM_KEYATTR_PERMANENT
,
830 CssmError::throwMe(status
);
831 freePublicKey
= true;
833 if (descriptiveData
.Data
!= NULL
)
834 free (descriptiveData
.Data
);
836 status
= CSSM_UnwrapKey(
840 privateWrappedKey
.KeyHeader
.KeyUsage
,
841 privateWrappedKey
.KeyHeader
.KeyAttr
| CSSM_KEYATTR_PERMANENT
,
848 CssmError::throwMe(status
);
850 if (descriptiveData
.Data
!= NULL
)
851 free (descriptiveData
.Data
);
853 freePrivateKey
= true;
855 // Find the keys we just generated in the DL to get SecKeyRefs to them
856 // so we can change the label to be the hash of the public key, and
857 // fix up other attributes.
859 // Look up public key in the DLDB.
860 DbAttributes pubDbAttributes
;
861 DbUniqueRecord pubUniqueId
;
862 SSDbCursor
dbPubCursor(ssDb
, 1);
863 dbPubCursor
->recordType(CSSM_DL_DB_RECORD_PUBLIC_KEY
);
864 dbPubCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, pubKeyHash
);
865 CssmClient::Key publicKey
;
866 if (!dbPubCursor
->nextKey(&pubDbAttributes
, publicKey
, pubUniqueId
))
867 MacOSError::throwMe(errSecItemNotFound
);
869 // Look up private key in the DLDB.
870 DbAttributes privDbAttributes
;
871 DbUniqueRecord privUniqueId
;
872 SSDbCursor
dbPrivCursor(ssDb
, 1);
873 dbPrivCursor
->recordType(CSSM_DL_DB_RECORD_PRIVATE_KEY
);
874 dbPrivCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, pubKeyHash
);
875 CssmClient::Key privateKey
;
876 if (!dbPrivCursor
->nextKey(&privDbAttributes
, privateKey
, privUniqueId
))
877 MacOSError::throwMe(errSecItemNotFound
);
879 // @@@ Not exception safe!
880 csp
.allocator().free(cssmData
->Data
);
881 csp
.allocator().free(cssmData
);
883 auto_ptr
<string
>privDescription
;
884 auto_ptr
<string
>pubDescription
;
886 privDescription
.reset(new string(initialAccess
->promptDescription()));
887 pubDescription
.reset(new string(initialAccess
->promptDescription()));
890 /* this path taken if no promptDescription available, e.g., for complex ACLs */
891 privDescription
.reset(new string("Private key"));
892 pubDescription
.reset(new string("Public key"));
895 // Set the label of the public key to the public key hash.
896 // Set the PrintName of the public key to the description in the acl.
897 pubDbAttributes
.add(kInfoKeyPrintName
, *pubDescription
);
898 pubUniqueId
->modify(CSSM_DL_DB_RECORD_PUBLIC_KEY
, &pubDbAttributes
, NULL
, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
);
900 // Set the label of the private key to the public key hash.
901 // Set the PrintName of the private key to the description in the acl.
902 privDbAttributes
.add(kInfoKeyPrintName
, *privDescription
);
903 privUniqueId
->modify(CSSM_DL_DB_RECORD_PRIVATE_KEY
, &privDbAttributes
, NULL
, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
);
905 // Finally fix the acl and owner of the private key to the specified access control settings.
906 initialAccess
->setAccess(*privateKey
, maker
);
908 // Make the public key acl completely open
909 SecPointer
<Access
> pubKeyAccess(new Access());
910 pubKeyAccess
->setAccess(*publicKey
, maker
);
912 // Create keychain items which will represent the keys.
913 publicKeyItem
= keychain
->item(CSSM_DL_DB_RECORD_PUBLIC_KEY
, pubUniqueId
);
914 privateKeyItem
= keychain
->item(CSSM_DL_DB_RECORD_PRIVATE_KEY
, privUniqueId
);
916 KeyItem
* impl
= dynamic_cast<KeyItem
*>(&(*publicKeyItem
));
919 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
);
924 impl
= dynamic_cast<KeyItem
*>(&(*privateKeyItem
));
927 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
);
929 outPrivateKey
= impl
;
934 CSSM_FreeKey(csp
->handle(), cred
, &publicCssmKey
, TRUE
);
936 CSSM_FreeKey(csp
->handle(), cred
, &privateCssmKey
, TRUE
);
939 CSSM_DeleteContext(ccHandle
);
945 CSSM_FreeKey(csp
->handle(), cred
, &publicCssmKey
, FALSE
);
947 CSSM_FreeKey(csp
->handle(), cred
, &privateCssmKey
, FALSE
);
950 CSSM_DeleteContext(ccHandle
);
952 if (keychain
&& publicKeyItem
&& privateKeyItem
)
954 KCEventNotifier::PostKeychainEvent(kSecAddEvent
, keychain
, publicKeyItem
);
955 KCEventNotifier::PostKeychainEvent(kSecAddEvent
, keychain
, privateKeyItem
);
960 KeyItem::generateWithAttributes(const SecKeychainAttributeList
*attrList
,
962 CSSM_ALGORITHMS algorithm
,
963 uint32 keySizeInBits
,
964 CSSM_CC_HANDLE contextHandle
,
965 CSSM_KEYUSE keyUsage
,
967 SecPointer
<Access
> initialAccess
)
969 CssmClient::CSP
appleCsp(gGuidAppleCSP
);
970 CssmClient::CSP
csp(NULL
);
972 uint8 labelBytes
[20];
973 CssmData
label(labelBytes
, sizeof(labelBytes
));
974 bool freeKey
= false;
975 bool deleteContext
= false;
976 const CSSM_DATA
*plabel
= NULL
;
980 if (!(keychain
->database()->dl()->subserviceMask() & CSSM_SERVICE_CSP
))
981 MacOSError::throwMe(errSecInvalidKeychain
);
983 SSDbImpl
* impl
= dynamic_cast<SSDbImpl
*>(&(*keychain
->database()));
986 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
);
990 csp
= keychain
->csp();
992 // Generate a random label to use initially
993 CssmClient::Random
random(appleCsp
, CSSM_ALGID_APPLE_YARROW
);
994 random
.generate(label
, (uint32
)label
.Length
);
999 // Not a persistent key so create it in the regular csp
1003 // Create a Access::Maker for the initial owner of the private key.
1004 ResourceControlContext
*prcc
= NULL
, rcc
;
1005 const AccessCredentials
*cred
= NULL
;
1006 Access::Maker maker
;
1007 if (keychain
&& initialAccess
)
1009 memset(&rcc
, 0, sizeof(rcc
));
1010 // @@@ Potentially provide a credential argument which allows us to generate keys in the csp.
1011 // Currently the CSP lets anyone do this, but we might restrict this in the future, e.g. a smartcard
1012 // could require out-of-band pin entry before a key can be generated.
1013 maker
.initialOwner(rcc
);
1014 // Create the cred we need to manipulate the keys until we actually set a new access control for them.
1015 cred
= maker
.cred();
1021 CSSM_CC_HANDLE ccHandle
= 0;
1028 ccHandle
= contextHandle
;
1031 status
= CSSM_CSP_CreateKeyGenContext(csp
->handle(), algorithm
, keySizeInBits
, NULL
, NULL
, NULL
, NULL
, NULL
, &ccHandle
);
1033 CssmError::throwMe(status
);
1034 deleteContext
= true;
1039 CSSM_DL_DB_HANDLE dldbHandle
= ssDb
->handle();
1040 CSSM_DL_DB_HANDLE_PTR dldbHandlePtr
= &dldbHandle
;
1041 CSSM_CONTEXT_ATTRIBUTE contextAttributes
= { CSSM_ATTRIBUTE_DL_DB_HANDLE
, sizeof(dldbHandle
), { (char *)dldbHandlePtr
} };
1042 status
= CSSM_UpdateContextAttributes(ccHandle
, 1, &contextAttributes
);
1044 CssmError::throwMe(status
);
1046 keyAttr
|= CSSM_KEYATTR_PERMANENT
;
1050 status
= CSSM_GenerateKey(ccHandle
, keyUsage
, keyAttr
, plabel
, prcc
, &cssmKey
);
1052 CssmError::throwMe(status
);
1057 // Find the key we just generated in the DL and get a SecKeyRef
1058 // so we can specify the label attribute(s) and initial ACL.
1060 // Look up key in the DLDB.
1061 DbAttributes dbAttributes
;
1062 DbUniqueRecord uniqueId
;
1063 SSDbCursor
dbCursor(ssDb
, 1);
1064 dbCursor
->recordType(CSSM_DL_DB_RECORD_SYMMETRIC_KEY
);
1065 dbCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, label
);
1066 CssmClient::Key key
;
1067 if (!dbCursor
->nextKey(&dbAttributes
, key
, uniqueId
))
1068 MacOSError::throwMe(errSecItemNotFound
);
1070 // Set the initial label, application label, and application tag (if provided)
1072 DbAttributes newDbAttributes
;
1073 SSDbCursor
otherDbCursor(ssDb
, 1);
1074 otherDbCursor
->recordType(CSSM_DL_DB_RECORD_SYMMETRIC_KEY
);
1075 bool checkForDuplicates
= false;
1077 for (UInt32 index
=0; index
< attrList
->count
; index
++) {
1078 SecKeychainAttribute attr
= attrList
->attr
[index
];
1079 CssmData
attrData(attr
.data
, attr
.length
);
1080 if (attr
.tag
== kSecKeyPrintName
) {
1081 newDbAttributes
.add(kInfoKeyPrintName
, attrData
);
1083 if (attr
.tag
== kSecKeyLabel
) {
1084 newDbAttributes
.add(kInfoKeyLabel
, attrData
);
1085 otherDbCursor
->add(CSSM_DB_EQUAL
, kInfoKeyLabel
, attrData
);
1086 checkForDuplicates
= true;
1088 if (attr
.tag
== kSecKeyApplicationTag
) {
1089 newDbAttributes
.add(kInfoKeyApplicationTag
, attrData
);
1090 otherDbCursor
->add(CSSM_DB_EQUAL
, kInfoKeyApplicationTag
, attrData
);
1091 checkForDuplicates
= true;
1095 DbAttributes otherDbAttributes
;
1096 DbUniqueRecord otherUniqueId
;
1097 CssmClient::Key otherKey
;
1098 if (checkForDuplicates
&& otherDbCursor
->nextKey(&otherDbAttributes
, otherKey
, otherUniqueId
))
1099 MacOSError::throwMe(errSecDuplicateItem
);
1101 uniqueId
->modify(CSSM_DL_DB_RECORD_SYMMETRIC_KEY
, &newDbAttributes
, NULL
, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
);
1104 // Finally, fix the acl and owner of the key to the specified access control settings.
1106 initialAccess
->setAccess(*key
, maker
);
1108 // Create keychain item which will represent the key.
1109 keyItem
= keychain
->item(CSSM_DL_DB_RECORD_SYMMETRIC_KEY
, uniqueId
);
1113 CssmClient::Key
tempKey(csp
, cssmKey
);
1114 keyItem
= new KeyItem(tempKey
);
1121 // Delete the key if something goes wrong so we don't end up with inaccessible keys in the database.
1122 CSSM_FreeKey(csp
->handle(), cred
, &cssmKey
, TRUE
);
1126 CSSM_DeleteContext(ccHandle
);
1133 CSSM_FreeKey(csp
->handle(), NULL
, &cssmKey
, FALSE
);
1137 CSSM_DeleteContext(ccHandle
);
1139 if (keychain
&& keyItem
)
1140 keychain
->postEvent(kSecAddEvent
, keyItem
);
1142 KeyItem
* item
= dynamic_cast<KeyItem
*>(&*keyItem
);
1145 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER
);
1152 KeyItem::generate(Keychain keychain
,
1153 CSSM_ALGORITHMS algorithm
,
1154 uint32 keySizeInBits
,
1155 CSSM_CC_HANDLE contextHandle
,
1156 CSSM_KEYUSE keyUsage
,
1158 SecPointer
<Access
> initialAccess
)
1160 return KeyItem::generateWithAttributes(NULL
, keychain
,
1161 algorithm
, keySizeInBits
, contextHandle
,
1162 keyUsage
, keyAttr
, initialAccess
);
1166 void KeyItem::RawSign(SecPadding padding
, CSSM_DATA dataToSign
, const AccessCredentials
*credentials
, CSSM_DATA
& signature
)
1168 CSSM_ALGORITHMS baseAlg
= key()->header().algorithm();
1170 if ((baseAlg
!= CSSM_ALGID_RSA
) && (baseAlg
!= CSSM_ALGID_ECDSA
))
1172 MacOSError::throwMe(errSecParam
);
1175 CSSM_ALGORITHMS paddingAlg
= CSSM_PADDING_PKCS1
;
1179 case kSecPaddingPKCS1
:
1181 paddingAlg
= CSSM_PADDING_PKCS1
;
1185 case kSecPaddingPKCS1MD2
:
1187 baseAlg
= CSSM_ALGID_MD2WithRSA
;
1191 case kSecPaddingPKCS1MD5
:
1193 baseAlg
= CSSM_ALGID_MD5WithRSA
;
1197 case kSecPaddingPKCS1SHA1
:
1199 baseAlg
= CSSM_ALGID_SHA1WithRSA
;
1205 paddingAlg
= CSSM_PADDING_NONE
;
1210 Sign
signContext(csp(), baseAlg
);
1211 signContext
.key(key());
1212 signContext
.set(CSSM_ATTRIBUTE_PADDING
, paddingAlg
);
1213 signContext
.cred(credentials
);
1215 CssmData
data(dataToSign
.Data
, dataToSign
.Length
);
1216 signContext
.sign(data
);
1218 CssmData
sig(signature
.Data
, signature
.Length
);
1219 signContext(sig
); // yes, this is an accessor. Believe it, or not.
1220 signature
.Length
= sig
.length();
1225 void KeyItem::RawVerify(SecPadding padding
, CSSM_DATA dataToVerify
, const AccessCredentials
*credentials
, CSSM_DATA sig
)
1227 CSSM_ALGORITHMS baseAlg
= key()->header().algorithm();
1228 if ((baseAlg
!= CSSM_ALGID_RSA
) && (baseAlg
!= CSSM_ALGID_ECDSA
))
1230 MacOSError::throwMe(errSecParam
);
1233 CSSM_ALGORITHMS paddingAlg
= CSSM_PADDING_PKCS1
;
1237 case kSecPaddingPKCS1
:
1239 paddingAlg
= CSSM_PADDING_PKCS1
;
1243 case kSecPaddingPKCS1MD2
:
1245 baseAlg
= CSSM_ALGID_MD2WithRSA
;
1249 case kSecPaddingPKCS1MD5
:
1251 baseAlg
= CSSM_ALGID_MD5WithRSA
;
1255 case kSecPaddingPKCS1SHA1
:
1257 baseAlg
= CSSM_ALGID_SHA1WithRSA
;
1263 paddingAlg
= CSSM_PADDING_NONE
;
1268 Verify
verifyContext(csp(), baseAlg
);
1269 verifyContext
.key(key());
1270 verifyContext
.set(CSSM_ATTRIBUTE_PADDING
, paddingAlg
);
1271 verifyContext
.cred(credentials
);
1273 CssmData
data(dataToVerify
.Data
, dataToVerify
.Length
);
1274 CssmData
signature(sig
.Data
, sig
.Length
);
1275 verifyContext
.verify(data
, signature
);
1280 void KeyItem::Encrypt(SecPadding padding
, CSSM_DATA dataToEncrypt
, const AccessCredentials
*credentials
, CSSM_DATA
& encryptedData
)
1282 CSSM_ALGORITHMS baseAlg
= key()->header().algorithm();
1283 if (baseAlg
!= CSSM_ALGID_RSA
)
1285 MacOSError::throwMe(errSecParam
);
1288 CSSM_ALGORITHMS paddingAlg
= CSSM_PADDING_PKCS1
;
1292 case kSecPaddingPKCS1
:
1294 paddingAlg
= CSSM_PADDING_PKCS1
;
1300 paddingAlg
= CSSM_PADDING_NONE
;
1305 CssmClient::Encrypt
encryptContext(csp(), baseAlg
);
1306 encryptContext
.key(key());
1307 encryptContext
.padding(paddingAlg
);
1308 encryptContext
.cred(credentials
);
1310 CssmData
inData(dataToEncrypt
.Data
, dataToEncrypt
.Length
);
1311 CssmData
outData(encryptedData
.Data
, encryptedData
.Length
);
1312 CssmData
remData((void*) NULL
, 0);
1314 encryptedData
.Length
= encryptContext
.encrypt(inData
, outData
, remData
);
1319 void KeyItem::Decrypt(SecPadding padding
, CSSM_DATA dataToDecrypt
, const AccessCredentials
*credentials
, CSSM_DATA
& decryptedData
)
1321 CSSM_ALGORITHMS baseAlg
= key()->header().algorithm();
1322 if (baseAlg
!= CSSM_ALGID_RSA
)
1324 MacOSError::throwMe(errSecParam
);
1327 CSSM_ALGORITHMS paddingAlg
= CSSM_PADDING_PKCS1
;
1331 case kSecPaddingPKCS1
:
1333 paddingAlg
= CSSM_PADDING_PKCS1
;
1340 paddingAlg
= CSSM_PADDING_NONE
;
1345 CssmClient::Decrypt
decryptContext(csp(), baseAlg
);
1346 decryptContext
.key(key());
1347 decryptContext
.padding(paddingAlg
);
1348 decryptContext
.cred(credentials
);
1350 CssmData
inData(dataToDecrypt
.Data
, dataToDecrypt
.Length
);
1351 CssmData
outData(decryptedData
.Data
, decryptedData
.Length
);
1352 CssmData
remData((void*) NULL
, 0);
1353 decryptedData
.Length
= decryptContext
.decrypt(inData
, outData
, remData
);
1354 if (remData
.Data
!= NULL
)
1360 CFHashCode
KeyItem::hash()
1362 CFHashCode result
= 0;
1363 const CSSM_KEY
*cssmKey
= key();
1364 if (NULL
!= cssmKey
)
1366 unsigned char digest
[CC_SHA256_DIGEST_LENGTH
];
1368 CFIndex size_of_data
= sizeof(CSSM_KEYHEADER
) + cssmKey
->KeyData
.Length
;
1370 CFMutableDataRef temp_cfdata
= CFDataCreateMutable(kCFAllocatorDefault
, size_of_data
);
1371 if (NULL
== temp_cfdata
)
1376 CFDataAppendBytes(temp_cfdata
, (const UInt8
*)cssmKey
, sizeof(CSSM_KEYHEADER
));
1377 CFDataAppendBytes(temp_cfdata
, cssmKey
->KeyData
.Data
, cssmKey
->KeyData
.Length
);
1379 if (size_of_data
< 80)
1381 // If it is less than 80 bytes then CFData can be used
1382 result
= CFHash(temp_cfdata
);
1383 CFRelease(temp_cfdata
);
1385 // CFData truncates its hash value to 80 bytes. ????
1386 // In order to do the 'right thing' a SHA 256 hash will be used to
1387 // include all of the data
1390 memset(digest
, 0, CC_SHA256_DIGEST_LENGTH
);
1392 CC_SHA256((const void *)CFDataGetBytePtr(temp_cfdata
), (CC_LONG
)CFDataGetLength(temp_cfdata
), digest
);
1394 CFDataRef data_to_hash
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
,
1395 (const UInt8
*)digest
, CC_SHA256_DIGEST_LENGTH
, kCFAllocatorNull
);
1396 result
= CFHash(data_to_hash
);
1397 CFRelease(data_to_hash
);
1398 CFRelease(temp_cfdata
);