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
);