2 * Copyright (c) 2002 Apple Computer, Inc. All Rights Reserved.
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
21 #include <Security/KeyItem.h>
22 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
23 #include <Security/cssmtype.h>
24 #include <Security/Access.h>
25 #include <Security/Keychains.h>
26 #include <Security/KeyItem.h>
27 #include <Security/wrapkey.h>
28 #include <Security/genkey.h>
29 #include <Security/globals.h>
30 #include "clNssUtils.h"
31 #include "KCEventNotifier.h"
33 // @@@ This needs to be shared.
34 static CSSM_DB_NAME_ATTR(kSecKeyPrintName
, 1, "PrintName", 0, NULL
, BLOB
);
35 static CSSM_DB_NAME_ATTR(kSecKeyLabel
, 6, "Label", 0, NULL
, BLOB
);
36 static CSSM_DB_NAME_ATTR(kSecApplicationTag
, 7, "ApplicationTag", 0, NULL
, BLOB
);
38 using namespace KeychainCore
;
40 KeyItem::KeyItem(const Keychain
&keychain
, const PrimaryKey
&primaryKey
, const CssmClient::DbUniqueRecord
&uniqueId
) :
41 ItemImpl(keychain
, primaryKey
, uniqueId
),
46 KeyItem::KeyItem(const Keychain
&keychain
, const PrimaryKey
&primaryKey
) :
47 ItemImpl(keychain
, primaryKey
),
52 KeyItem::KeyItem(KeyItem
&keyItem
) :
56 // @@@ this doesn't work for keys that are not in a keychain.
59 KeyItem::KeyItem(const CssmClient::Key
&key
) :
60 ItemImpl(key
->keyClass() + CSSM_DL_DB_RECORD_PUBLIC_KEY
, (OSType
)0, (UInt32
)0, (const void*)NULL
),
63 if (key
->keyClass() > CSSM_KEYCLASS_SESSION_KEY
)
64 MacOSError::throwMe(paramErr
);
67 KeyItem::~KeyItem() throw()
78 KeyItem::copyTo(const Keychain
&keychain
, Access
*newAccess
)
80 if (!keychain
->database()->dl()->subserviceMask() & CSSM_SERVICE_CSP
)
81 MacOSError::throwMe(errSecInvalidKeychain
);
83 /* Get the destination keychains db. */
84 SSDb
ssDb(safe_cast
<SSDbImpl
*>(&(*keychain
->database())));
86 /* Make sure mKey is valid. */
89 // Generate a random label to use initially
90 CssmClient::CSP
appleCsp(gGuidAppleCSP
);
91 CssmClient::Random
random(appleCsp
, CSSM_ALGID_APPLE_YARROW
);
93 CssmData
label(labelBytes
, sizeof(labelBytes
));
94 random
.generate(label
, label
.Length
);
96 /* Set up the ACL for the new key. */
97 SecPointer
<Access
> access
;
101 access
= new Access(*mKey
);
103 /* Generate a random 3DES wrapping Key. */
104 CssmClient::GenerateKey
genKey(csp(), CSSM_ALGID_3DES_3KEY
, 192);
105 CssmClient::Key
wrappingKey(genKey(KeySpec(CSSM_KEYUSE_WRAP
| CSSM_KEYUSE_UNWRAP
,
106 CSSM_KEYATTR_EXTRACTABLE
/* | CSSM_KEYATTR_RETURN_DATA */)));
108 /* Extract the key by wrapping it with the wrapping key. */
109 CssmClient::WrapKey
wrap(csp(), CSSM_ALGID_3DES_3KEY_EDE
);
110 wrap
.key(wrappingKey
);
111 wrap
.cred(getCredentials(CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED
, kSecCredentialTypeDefault
));
112 wrap
.mode(CSSM_ALGMODE_ECBPad
);
113 wrap
.padding(CSSM_PADDING_PKCS7
);
114 CssmClient::Key
wrappedKey(wrap(mKey
));
116 /* Unwrap the new key into the new Keychain. */
117 CssmClient::UnwrapKey
unwrap(keychain
->csp(), CSSM_ALGID_3DES_3KEY_EDE
);
118 unwrap
.key(wrappingKey
);
119 unwrap
.mode(CSSM_ALGMODE_ECBPad
);
120 unwrap
.padding(CSSM_PADDING_PKCS7
);
122 /* Setup the dldbHandle in the context. */
123 unwrap
.add(CSSM_ATTRIBUTE_DL_DB_HANDLE
, ssDb
->handle());
125 /* Set up an initial aclEntry so we can change it after the unwrap. */
127 ResourceControlContext rcc
;
128 maker
.initialOwner(rcc
, NULL
);
129 unwrap
.aclEntry(rcc
.input());
131 /* Unwrap the key. */
132 uint32 usage
= mKey
->usage();
133 /* Work around csp brokeness where it sets all usage bits in the Keyheader when CSSM_KEYUSE_ANY is set. */
134 if (usage
& CSSM_KEYUSE_ANY
)
135 usage
= CSSM_KEYUSE_ANY
;
137 CssmClient::Key
unwrappedKey(unwrap(wrappedKey
, KeySpec(usage
,
138 (mKey
->attributes() | CSSM_KEYATTR_PERMANENT
) & ~(CSSM_KEYATTR_ALWAYS_SENSITIVE
| CSSM_KEYATTR_NEVER_EXTRACTABLE
),
141 /* Look up unwrapped key in the DLDB. */
142 DbUniqueRecord uniqueId
;
143 SSDbCursor
dbCursor(ssDb
, 1);
144 dbCursor
->recordType(recordType());
145 dbCursor
->add(CSSM_DB_EQUAL
, kSecKeyLabel
, label
);
146 CssmClient::Key copiedKey
;
147 if (!dbCursor
->nextKey(NULL
, copiedKey
, uniqueId
))
148 MacOSError::throwMe(errSecItemNotFound
);
150 /* Copy the Label, PrintName and ApplicationTag attributes from the old key to the new one. */
152 DbAttributes
oldDbAttributes(mUniqueId
->database(), 3);
153 oldDbAttributes
.add(kSecKeyLabel
);
154 oldDbAttributes
.add(kSecKeyPrintName
);
155 oldDbAttributes
.add(kSecApplicationTag
);
156 mUniqueId
->get(&oldDbAttributes
, NULL
);
157 uniqueId
->modify(recordType(), &oldDbAttributes
, NULL
, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
);
159 /* Set the acl and owner on the unwrapped key. */
160 access
->setAccess(*unwrappedKey
, maker
);
162 /* Return a keychain items which represents the new key. */
163 Item
item(keychain
->item(recordType(), uniqueId
));
165 KCEventNotifier::PostKeychainEvent(kSecAddEvent
, keychain
, item
);
176 KeyItem::add(Keychain
&keychain
)
178 MacOSError::throwMe(unimpErr
);
181 CssmClient::SSDbUniqueRecord
182 KeyItem::ssDbUniqueRecord()
184 DbUniqueRecordImpl
*impl
= &*dbUniqueRecord();
185 return CssmClient::SSDbUniqueRecord(safe_cast
<Security::CssmClient::SSDbUniqueRecordImpl
*>(impl
));
193 CssmClient::SSDbUniqueRecord
uniqueId(ssDbUniqueRecord());
194 CssmDataContainer
dataBlob(uniqueId
->allocator());
195 uniqueId
->get(NULL
, &dataBlob
);
196 mKey
= CssmClient::Key(uniqueId
->database()->csp(), *reinterpret_cast<CssmKey
*>(dataBlob
.Data
));
209 const CSSM_X509_ALGORITHM_IDENTIFIER
&
210 KeyItem::algorithmIdentifier()
214 CSSM_KEY_TYPE algorithm
215 CSSM_KEY_PTR cssmKey
= (CSSM_KEY_PTR
)thisData
->Data
;
217 static void printKeyHeader(
218 const CSSM_KEYHEADER
&hdr
)
220 printf(" Algorithm : ");
221 switch(hdr
.AlgorithmId
) {
222 CSSM_X509_ALGORITHM_IDENTIFIER algID
;
224 CSSM_OID
*CL_algToOid(
225 CSSM_ALGORITHMS algId
)
226 typedef struct cssm_x509_algorithm_identifier
{
228 CSSM_DATA parameters
;
229 } CSSM_X509_ALGORITHM_IDENTIFIER
, *CSSM_X509_ALGORITHM_IDENTIFIER_PTR
;
236 KeyItem::strengthInBits(const CSSM_X509_ALGORITHM_IDENTIFIER
*algid
)
238 // @@@ Make a context with key based on algid and use that to get the effective keysize and not just the logical one.
239 CSSM_KEY_SIZE keySize
= {};
240 CSSM_RETURN rv
= CSSM_QueryKeySizeInBits (csp()->handle(),
247 return keySize
.LogicalKeySizeInBits
;
250 const AccessCredentials
*
251 KeyItem::getCredentials(
252 CSSM_ACL_AUTHORIZATION_TAG operation
,
253 SecCredentialType credentialType
)
255 // @@@ Fix this to actually examine the ACL for this key and consider operation and do the right thing.
256 //AutoAclEntryInfoList aclInfos;
257 //key()->getAcl(aclInfos);
260 switch (credentialType
)
262 case kSecCredentialTypeDefault
:
263 return globals().credentials();
264 case kSecCredentialTypeWithUI
:
265 return factory
.promptCred();
266 case kSecCredentialTypeNoUI
:
267 return factory
.nullCred();
269 MacOSError::throwMe(paramErr
);
276 CSSM_ALGORITHMS algorithm
,
277 uint32 keySizeInBits
,
278 CSSM_CC_HANDLE contextHandle
,
279 CSSM_KEYUSE publicKeyUsage
,
280 uint32 publicKeyAttr
,
281 CSSM_KEYUSE privateKeyUsage
,
282 uint32 privateKeyAttr
,
283 SecPointer
<Access
> initialAccess
,
284 SecPointer
<KeyItem
> &outPublicKey
,
285 SecPointer
<KeyItem
> &outPrivateKey
)
287 bool freeKeys
= false;
288 bool deleteContext
= false;
290 if (!keychain
->database()->dl()->subserviceMask() & CSSM_SERVICE_CSP
)
291 MacOSError::throwMe(errSecInvalidKeychain
);
293 SSDb
ssDb(safe_cast
<SSDbImpl
*>(&(*keychain
->database())));
294 CssmClient::CSP
csp(keychain
->csp());
295 CssmClient::CSP
appleCsp(gGuidAppleCSP
);
297 // Generate a random label to use initially
298 CssmClient::Random
random(appleCsp
, CSSM_ALGID_APPLE_YARROW
);
299 uint8 labelBytes
[20];
300 CssmData
label(labelBytes
, sizeof(labelBytes
));
301 random
.generate(label
, label
.Length
);
303 // Create a Access::Maker for the initial owner of the private key.
304 ResourceControlContext rcc
;
305 memset(&rcc
, 0, sizeof(rcc
));
307 // @@@ 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.
308 maker
.initialOwner(rcc
);
309 // Create the cred we need to manipulate the keys until we actually set a new access control for them.
310 const AccessCredentials
*cred
= maker
.cred();
312 CSSM_KEY publicCssmKey
, privateCssmKey
;
313 memset(&publicCssmKey
, 0, sizeof(publicCssmKey
));
314 memset(&privateCssmKey
, 0, sizeof(privateCssmKey
));
316 CSSM_CC_HANDLE ccHandle
= 0;
322 ccHandle
= contextHandle
;
325 status
= CSSM_CSP_CreateKeyGenContext(csp
->handle(), algorithm
, keySizeInBits
, NULL
, NULL
, NULL
, NULL
, NULL
, &ccHandle
);
327 CssmError::throwMe(status
);
328 deleteContext
= true;
331 CSSM_DL_DB_HANDLE dldbHandle
= ssDb
->handle();
332 CSSM_DL_DB_HANDLE_PTR dldbHandlePtr
= &dldbHandle
;
333 CSSM_CONTEXT_ATTRIBUTE contextAttributes
= { CSSM_ATTRIBUTE_DL_DB_HANDLE
, sizeof(dldbHandle
), { (char *)dldbHandlePtr
} };
334 status
= CSSM_UpdateContextAttributes(ccHandle
, 1, &contextAttributes
);
336 CssmError::throwMe(status
);
338 // Generate the keypair
339 status
= CSSM_GenerateKeyPair(ccHandle
, publicKeyUsage
, publicKeyAttr
, &label
, &publicCssmKey
, privateKeyUsage
, privateKeyAttr
, &label
, &rcc
, &privateCssmKey
);
341 CssmError::throwMe(status
);
344 // Find the keys we just generated in the DL to get SecKeyRef's to them
345 // so we can change the label to be the hash of the public key, and
346 // fix up other attributes.
348 // Look up public key in the DLDB.
349 DbAttributes pubDbAttributes
;
350 DbUniqueRecord pubUniqueId
;
351 SSDbCursor
dbPubCursor(ssDb
, 1);
352 dbPubCursor
->recordType(CSSM_DL_DB_RECORD_PUBLIC_KEY
);
353 dbPubCursor
->add(CSSM_DB_EQUAL
, kSecKeyLabel
, label
);
354 CssmClient::Key publicKey
;
355 if (!dbPubCursor
->nextKey(&pubDbAttributes
, publicKey
, pubUniqueId
))
356 MacOSError::throwMe(errSecItemNotFound
);
358 // Look up private key in the DLDB.
359 DbAttributes privDbAttributes
;
360 DbUniqueRecord privUniqueId
;
361 SSDbCursor
dbPrivCursor(ssDb
, 1);
362 dbPrivCursor
->recordType(CSSM_DL_DB_RECORD_PRIVATE_KEY
);
363 dbPrivCursor
->add(CSSM_DB_EQUAL
, kSecKeyLabel
, label
);
364 CssmClient::Key privateKey
;
365 if (!dbPrivCursor
->nextKey(&privDbAttributes
, privateKey
, privUniqueId
))
366 MacOSError::throwMe(errSecItemNotFound
);
368 // Convert reference public key to a raw key so we can use it
370 CssmClient::WrapKey
wrap(csp
, CSSM_ALGID_NONE
);
372 CssmClient::Key rawPubKey
= wrap(publicKey
);
374 // Calculate the hash of the public key using the appleCSP.
375 CssmClient::PassThrough
passThrough(appleCsp
);
379 /* Given a CSSM_KEY_PTR in any format, obtain the SHA-1 hash of the
380 * associated key blob.
381 * Key is specified in CSSM_CSP_CreatePassThroughContext.
382 * Hash is allocated bythe CSP, in the App's memory, and returned
384 passThrough
.key(rawPubKey
);
385 passThrough(CSSM_APPLECSP_KEYDIGEST
, NULL
, &outData
);
386 cssmData
= reinterpret_cast<CssmData
*>(outData
);
387 CssmData
&pubKeyHash
= *cssmData
;
389 std::string
description(initialAccess
->promptDescription());
390 // Set the label of the public key to the public key hash.
391 // Set the PrintName of the public key to the description in the acl.
392 pubDbAttributes
.add(kSecKeyLabel
, pubKeyHash
);
393 pubDbAttributes
.add(kSecKeyPrintName
, description
);
394 pubUniqueId
->modify(CSSM_DL_DB_RECORD_PUBLIC_KEY
, &pubDbAttributes
, NULL
, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
);
396 // Set the label of the private key to the public key hash.
397 // Set the PrintName of the private key to the description in the acl.
398 privDbAttributes
.add(kSecKeyLabel
, pubKeyHash
);
399 privDbAttributes
.add(kSecKeyPrintName
, description
);
400 privUniqueId
->modify(CSSM_DL_DB_RECORD_PRIVATE_KEY
, &privDbAttributes
, NULL
, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
);
402 // @@@ Not exception safe!
403 csp
.allocator().free(cssmData
->Data
);
404 csp
.allocator().free(cssmData
);
406 // Finally fix the acl and owner of the private key to the specified access control settings.
407 initialAccess
->setAccess(*privateKey
, maker
);
409 // Make the public key acl completely open
411 pubKeyAccess
.setAccess(*publicKey
, maker
);
413 // Create keychain items which will represent the keys.
414 outPublicKey
= safe_cast
<KeyItem
*>(&(*keychain
->item(CSSM_DL_DB_RECORD_PUBLIC_KEY
, pubUniqueId
)));
415 outPrivateKey
= safe_cast
<KeyItem
*>(&(*keychain
->item(CSSM_DL_DB_RECORD_PRIVATE_KEY
, privUniqueId
)));
421 // Delete the keys if something goes wrong so we don't end up with inaccesable keys in the database.
422 CSSM_FreeKey(csp
->handle(), cred
, &publicCssmKey
, TRUE
);
423 CSSM_FreeKey(csp
->handle(), cred
, &privateCssmKey
, TRUE
);
427 CSSM_DeleteContext(ccHandle
);
434 CSSM_FreeKey(csp
->handle(), NULL
, &publicCssmKey
, FALSE
);
435 CSSM_FreeKey(csp
->handle(), NULL
, &privateCssmKey
, FALSE
);
439 CSSM_DeleteContext(ccHandle
);
445 const CSSM_KEY
&publicWrappedKey
,
446 const CSSM_KEY
&privateWrappedKey
,
447 SecPointer
<Access
> initialAccess
,
448 SecPointer
<KeyItem
> &outPublicKey
,
449 SecPointer
<KeyItem
> &outPrivateKey
)
451 bool freePublicKey
= false;
452 bool freePrivateKey
= false;
453 bool deleteContext
= false;
455 if (!keychain
->database()->dl()->subserviceMask() & CSSM_SERVICE_CSP
)
456 MacOSError::throwMe(errSecInvalidKeychain
);
458 SSDb
ssDb(safe_cast
<SSDbImpl
*>(&(*keychain
->database())));
459 CssmClient::CSP
csp(keychain
->csp());
460 CssmClient::CSP
appleCsp(gGuidAppleCSP
);
462 // Create a Access::Maker for the initial owner of the private key.
463 ResourceControlContext rcc
;
464 memset(&rcc
, 0, sizeof(rcc
));
466 // @@@ Potentially provide a credential argument which allows us to unwrap 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.
467 maker
.initialOwner(rcc
);
468 // Create the cred we need to manipulate the keys until we actually set a new access control for them.
469 const AccessCredentials
*cred
= maker
.cred();
471 CSSM_KEY publicCssmKey
, privateCssmKey
;
472 memset(&publicCssmKey
, 0, sizeof(publicCssmKey
));
473 memset(&privateCssmKey
, 0, sizeof(privateCssmKey
));
475 CSSM_CC_HANDLE ccHandle
= 0;
481 // Calculate the hash of the public key using the appleCSP.
482 CssmClient::PassThrough
passThrough(appleCsp
);
486 /* Given a CSSM_KEY_PTR in any format, obtain the SHA-1 hash of the
487 * associated key blob.
488 * Key is specified in CSSM_CSP_CreatePassThroughContext.
489 * Hash is allocated bythe CSP, in the App's memory, and returned
491 passThrough
.key(&publicWrappedKey
);
492 passThrough(CSSM_APPLECSP_KEYDIGEST
, NULL
, &outData
);
493 cssmData
= reinterpret_cast<CssmData
*>(outData
);
494 CssmData
&pubKeyHash
= *cssmData
;
496 status
= CSSM_CSP_CreateSymmetricContext(csp
->handle(), publicWrappedKey
.KeyHeader
.WrapAlgorithmId
, CSSM_ALGMODE_NONE
, NULL
, NULL
, NULL
, CSSM_PADDING_NONE
, NULL
, &ccHandle
);
498 CssmError::throwMe(status
);
499 deleteContext
= true;
501 CSSM_DL_DB_HANDLE dldbHandle
= ssDb
->handle();
502 CSSM_DL_DB_HANDLE_PTR dldbHandlePtr
= &dldbHandle
;
503 CSSM_CONTEXT_ATTRIBUTE contextAttributes
= { CSSM_ATTRIBUTE_DL_DB_HANDLE
, sizeof(dldbHandle
), { (char *)dldbHandlePtr
} };
504 status
= CSSM_UpdateContextAttributes(ccHandle
, 1, &contextAttributes
);
506 CssmError::throwMe(status
);
508 // Unwrap the the keys
509 CSSM_DATA descriptiveData
= {0, NULL
};
511 status
= CSSM_UnwrapKey(
515 publicWrappedKey
.KeyHeader
.KeyUsage
,
516 publicWrappedKey
.KeyHeader
.KeyAttr
| CSSM_KEYATTR_PERMANENT
,
523 CssmError::throwMe(status
);
524 freePublicKey
= true;
526 if (descriptiveData
.Data
!= NULL
)
527 free (descriptiveData
.Data
);
529 status
= CSSM_UnwrapKey(
533 privateWrappedKey
.KeyHeader
.KeyUsage
,
534 privateWrappedKey
.KeyHeader
.KeyAttr
| CSSM_KEYATTR_PERMANENT
,
541 CssmError::throwMe(status
);
543 if (descriptiveData
.Data
!= NULL
)
544 free (descriptiveData
.Data
);
546 freePrivateKey
= true;
548 // Find the keys we just generated in the DL to get SecKeyRef's to them
549 // so we can change the label to be the hash of the public key, and
550 // fix up other attributes.
552 // Look up public key in the DLDB.
553 DbAttributes pubDbAttributes
;
554 DbUniqueRecord pubUniqueId
;
555 SSDbCursor
dbPubCursor(ssDb
, 1);
556 dbPubCursor
->recordType(CSSM_DL_DB_RECORD_PUBLIC_KEY
);
557 dbPubCursor
->add(CSSM_DB_EQUAL
, kSecKeyLabel
, pubKeyHash
);
558 CssmClient::Key publicKey
;
559 if (!dbPubCursor
->nextKey(&pubDbAttributes
, publicKey
, pubUniqueId
))
560 MacOSError::throwMe(errSecItemNotFound
);
562 // Look up private key in the DLDB.
563 DbAttributes privDbAttributes
;
564 DbUniqueRecord privUniqueId
;
565 SSDbCursor
dbPrivCursor(ssDb
, 1);
566 dbPrivCursor
->recordType(CSSM_DL_DB_RECORD_PRIVATE_KEY
);
567 dbPrivCursor
->add(CSSM_DB_EQUAL
, kSecKeyLabel
, pubKeyHash
);
568 CssmClient::Key privateKey
;
569 if (!dbPrivCursor
->nextKey(&privDbAttributes
, privateKey
, privUniqueId
))
570 MacOSError::throwMe(errSecItemNotFound
);
572 // @@@ Not exception safe!
573 csp
.allocator().free(cssmData
->Data
);
574 csp
.allocator().free(cssmData
);
576 std::string
description(initialAccess
->promptDescription());
577 // Set the label of the public key to the public key hash.
578 // Set the PrintName of the public key to the description in the acl.
579 pubDbAttributes
.add(kSecKeyPrintName
, description
);
580 pubUniqueId
->modify(CSSM_DL_DB_RECORD_PUBLIC_KEY
, &pubDbAttributes
, NULL
, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
);
582 // Set the label of the private key to the public key hash.
583 // Set the PrintName of the private key to the description in the acl.
584 privDbAttributes
.add(kSecKeyPrintName
, description
);
585 privUniqueId
->modify(CSSM_DL_DB_RECORD_PRIVATE_KEY
, &privDbAttributes
, NULL
, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE
);
587 // Finally fix the acl and owner of the private key to the specified access control settings.
588 initialAccess
->setAccess(*privateKey
, maker
);
590 // Make the public key acl completely open
592 pubKeyAccess
.setAccess(*publicKey
, maker
);
594 // Create keychain items which will represent the keys.
595 outPublicKey
= safe_cast
<KeyItem
*>(&(*keychain
->item(CSSM_DL_DB_RECORD_PUBLIC_KEY
, pubUniqueId
)));
596 outPrivateKey
= safe_cast
<KeyItem
*>(&(*keychain
->item(CSSM_DL_DB_RECORD_PRIVATE_KEY
, privUniqueId
)));
601 CSSM_FreeKey(csp
->handle(), cred
, &publicCssmKey
, TRUE
);
603 CSSM_FreeKey(csp
->handle(), cred
, &privateCssmKey
, TRUE
);
606 CSSM_DeleteContext(ccHandle
);
612 CSSM_FreeKey(csp
->handle(), cred
, &publicCssmKey
, FALSE
);
614 CSSM_FreeKey(csp
->handle(), cred
, &privateCssmKey
, FALSE
);
617 CSSM_DeleteContext(ccHandle
);
621 KeyItem::generate(Keychain keychain
,
622 CSSM_ALGORITHMS algorithm
,
623 uint32 keySizeInBits
,
624 CSSM_CC_HANDLE contextHandle
,
625 CSSM_KEYUSE keyUsage
,
627 SecPointer
<Access
> initialAccess
)
629 CssmClient::CSP
appleCsp(gGuidAppleCSP
);
630 CssmClient::CSP
csp(NULL
);
632 uint8 labelBytes
[20];
633 CssmData
label(labelBytes
, sizeof(labelBytes
));
634 bool freeKey
= false;
635 bool deleteContext
= false;
636 const CSSM_DATA
*plabel
= NULL
;
641 if (!keychain
->database()->dl()->subserviceMask() & CSSM_SERVICE_CSP
)
642 MacOSError::throwMe(errSecInvalidKeychain
);
644 ssDb
= SSDb(safe_cast
<SSDbImpl
*>(&(*keychain
->database())));
645 csp
= keychain
->csp();
647 // Generate a random label to use initially
648 CssmClient::Random
random(appleCsp
, CSSM_ALGID_APPLE_YARROW
);
649 random
.generate(label
, label
.Length
);
654 // Not a persistant key so create it in the regular csp
658 // Create a Access::Maker for the initial owner of the private key.
659 ResourceControlContext
*prcc
= NULL
, rcc
;
660 const AccessCredentials
*cred
= NULL
;
662 if (keychain
&& initialAccess
)
664 memset(&rcc
, 0, sizeof(rcc
));
665 // @@@ 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.
666 maker
.initialOwner(rcc
);
667 // Create the cred we need to manipulate the keys until we actually set a new access control for them.
674 CSSM_CC_HANDLE ccHandle
= 0;
680 ccHandle
= contextHandle
;
683 status
= CSSM_CSP_CreateKeyGenContext(csp
->handle(), algorithm
, keySizeInBits
, NULL
, NULL
, NULL
, NULL
, NULL
, &ccHandle
);
685 CssmError::throwMe(status
);
686 deleteContext
= true;
691 CSSM_DL_DB_HANDLE dldbHandle
= ssDb
->handle();
692 CSSM_DL_DB_HANDLE_PTR dldbHandlePtr
= &dldbHandle
;
693 CSSM_CONTEXT_ATTRIBUTE contextAttributes
= { CSSM_ATTRIBUTE_DL_DB_HANDLE
, sizeof(dldbHandle
), { (char *)dldbHandlePtr
} };
694 status
= CSSM_UpdateContextAttributes(ccHandle
, 1, &contextAttributes
);
696 CssmError::throwMe(status
);
698 keyAttr
|= CSSM_KEYATTR_PERMANENT
;
702 status
= CSSM_GenerateKey(ccHandle
, keyUsage
, keyAttr
, plabel
, prcc
, &cssmKey
);
704 CssmError::throwMe(status
);
709 // Find the keys we just generated in the DL to get SecKeyRef's to them
710 // so we can change the label to be the hash of the public key, and
711 // fix up other attributes.
713 // Look up key in the DLDB.
714 DbAttributes dbAttributes
;
715 DbUniqueRecord uniqueId
;
716 SSDbCursor
dbCursor(ssDb
, 1);
717 dbCursor
->recordType(CSSM_DL_DB_RECORD_SYMMETRIC_KEY
);
718 dbCursor
->add(CSSM_DB_EQUAL
, kSecKeyLabel
, label
);
720 if (!dbCursor
->nextKey(&dbAttributes
, key
, uniqueId
))
721 MacOSError::throwMe(errSecItemNotFound
);
723 // Finally fix the acl and owner of the key to the specified access control settings.
725 initialAccess
->setAccess(*key
, maker
);
727 // Create keychain items which will represent the keys.
728 outKey
= safe_cast
<KeyItem
*>(&(*keychain
->item(CSSM_DL_DB_RECORD_SYMMETRIC_KEY
, uniqueId
)));
732 CssmClient::Key
tempKey(csp
, cssmKey
);
733 outKey
= new KeyItem(tempKey
);
740 // Delete the keys if something goes wrong so we don't end up with inaccesable keys in the database.
741 CSSM_FreeKey(csp
->handle(), cred
, &cssmKey
, TRUE
);
745 CSSM_DeleteContext(ccHandle
);
752 CSSM_FreeKey(csp
->handle(), NULL
, &cssmKey
, FALSE
);
756 CSSM_DeleteContext(ccHandle
);