]> git.saurik.com Git - apple/security.git/blob - libsecurity_keychain/lib/KeyItem.cpp
0b7149d0770188d89a009a29f39ba4a597a8dd61
[apple/security.git] / libsecurity_keychain / lib / KeyItem.cpp
1 /*
2 * Copyright (c) 2002-2004 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 //
25 // KeyItem.cpp
26 //
27 #include <security_keychain/KeyItem.h>
28 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
29 #include <Security/cssmtype.h>
30 #include <security_keychain/Access.h>
31 #include <security_keychain/Keychains.h>
32 #include <security_keychain/KeyItem.h>
33 #include <security_cdsa_client/wrapkey.h>
34 #include <security_cdsa_client/genkey.h>
35 #include <security_cdsa_client/signclient.h>
36 #include <security_cdsa_client/cryptoclient.h>
37
38 #include <security_keychain/Globals.h>
39 #include "KCEventNotifier.h"
40
41 // @@@ This needs to be shared.
42 static CSSM_DB_NAME_ATTR(kInfoKeyPrintName, kSecKeyPrintName, (char*) "PrintName", 0, NULL, BLOB);
43 static CSSM_DB_NAME_ATTR(kInfoKeyLabel, kSecKeyLabel, (char*) "Label", 0, NULL, BLOB);
44 static CSSM_DB_NAME_ATTR(kInfoKeyApplicationTag, kSecKeyApplicationTag, (char*) "ApplicationTag", 0, NULL, BLOB);
45
46 using namespace KeychainCore;
47 using namespace CssmClient;
48
49 KeyItem::KeyItem(const Keychain &keychain, const PrimaryKey &primaryKey, const CssmClient::DbUniqueRecord &uniqueId) :
50 ItemImpl(keychain, primaryKey, uniqueId),
51 mKey(),
52 algid(NULL),
53 mPubKeyHash(Allocator::standard())
54 {
55 }
56
57 KeyItem::KeyItem(const Keychain &keychain, const PrimaryKey &primaryKey) :
58 ItemImpl(keychain, primaryKey),
59 mKey(),
60 algid(NULL),
61 mPubKeyHash(Allocator::standard())
62 {
63 }
64
65 KeyItem* KeyItem::make(const Keychain &keychain, const PrimaryKey &primaryKey, const CssmClient::DbUniqueRecord &uniqueId)
66 {
67 KeyItem* k = new KeyItem(keychain, primaryKey, uniqueId);
68 keychain->addItem(primaryKey, k);
69 return k;
70 }
71
72
73
74 KeyItem* KeyItem::make(const Keychain &keychain, const PrimaryKey &primaryKey)
75 {
76 KeyItem* k = new KeyItem(keychain, primaryKey);
77 keychain->addItem(primaryKey, k);
78 return k;
79 }
80
81
82
83 KeyItem::KeyItem(KeyItem &keyItem) :
84 ItemImpl(keyItem),
85 mKey(),
86 algid(NULL),
87 mPubKeyHash(Allocator::standard())
88 {
89 // @@@ this doesn't work for keys that are not in a keychain.
90 }
91
92 KeyItem::KeyItem(const CssmClient::Key &key) :
93 ItemImpl(key->keyClass() + CSSM_DL_DB_RECORD_PUBLIC_KEY, (OSType)0, (UInt32)0, (const void*)NULL),
94 mKey(key),
95 algid(NULL),
96 mPubKeyHash(Allocator::standard())
97 {
98 if (key->keyClass() > CSSM_KEYCLASS_SESSION_KEY)
99 MacOSError::throwMe(paramErr);
100 }
101
102 KeyItem::~KeyItem()
103 {
104 }
105
106 void
107 KeyItem::update()
108 {
109 ItemImpl::update();
110 }
111
112 Item
113 KeyItem::copyTo(const Keychain &keychain, Access *newAccess)
114 {
115 if (!(keychain->database()->dl()->subserviceMask() & CSSM_SERVICE_CSP))
116 MacOSError::throwMe(errSecInvalidKeychain);
117
118 /* Get the destination keychain's db. */
119 SSDbImpl* dbImpl = dynamic_cast<SSDbImpl*>(&(*keychain->database()));
120 if (dbImpl == NULL)
121 {
122 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER);
123 }
124
125 SSDb ssDb(dbImpl);
126
127 /* Make sure mKey is valid. */
128 key();
129
130 // Generate a random label to use initially
131 CssmClient::CSP appleCsp(gGuidAppleCSP);
132 CssmClient::Random random(appleCsp, CSSM_ALGID_APPLE_YARROW);
133 uint8 labelBytes[20];
134 CssmData label(labelBytes, sizeof(labelBytes));
135 random.generate(label, label.Length);
136
137 /* Set up the ACL for the new key. */
138 SecPointer<Access> access;
139 if (newAccess)
140 access = newAccess;
141 else
142 access = new Access(*mKey);
143
144 /* Generate a random 3DES wrapping Key. */
145 CssmClient::GenerateKey genKey(csp(), CSSM_ALGID_3DES_3KEY, 192);
146 CssmClient::Key wrappingKey(genKey(KeySpec(CSSM_KEYUSE_WRAP | CSSM_KEYUSE_UNWRAP,
147 CSSM_KEYATTR_EXTRACTABLE /* | CSSM_KEYATTR_RETURN_DATA */)));
148
149 /* make a random IV */
150 uint8 ivBytes[8];
151 CssmData iv(ivBytes, sizeof(ivBytes));
152 random.generate(iv, iv.length());
153
154 /* Extract the key by wrapping it with the wrapping key. */
155 CssmClient::WrapKey wrap(csp(), CSSM_ALGID_3DES_3KEY_EDE);
156 wrap.key(wrappingKey);
157 wrap.cred(getCredentials(CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED, kSecCredentialTypeDefault));
158 wrap.mode(CSSM_ALGMODE_ECBPad);
159 wrap.padding(CSSM_PADDING_PKCS7);
160 wrap.initVector(iv);
161 CssmClient::Key wrappedKey(wrap(mKey));
162
163 /* Unwrap the new key into the new Keychain. */
164 CssmClient::UnwrapKey unwrap(keychain->csp(), CSSM_ALGID_3DES_3KEY_EDE);
165 unwrap.key(wrappingKey);
166 unwrap.mode(CSSM_ALGMODE_ECBPad);
167 unwrap.padding(CSSM_PADDING_PKCS7);
168 unwrap.initVector(iv);
169
170 /* Setup the dldbHandle in the context. */
171 unwrap.add(CSSM_ATTRIBUTE_DL_DB_HANDLE, ssDb->handle());
172
173 /* Set up an initial aclEntry so we can change it after the unwrap. */
174 Access::Maker maker(Allocator::standard(), Access::Maker::kAnyMakerType);
175 ResourceControlContext rcc;
176 maker.initialOwner(rcc, NULL);
177 unwrap.owner(rcc.input());
178
179 /* Unwrap the key. */
180 uint32 usage = mKey->usage();
181 /* Work around csp brokeness where it sets all usage bits in the Keyheader when CSSM_KEYUSE_ANY is set. */
182 if (usage & CSSM_KEYUSE_ANY)
183 usage = CSSM_KEYUSE_ANY;
184
185 CssmClient::Key unwrappedKey(unwrap(wrappedKey, KeySpec(usage,
186 (mKey->attributes() | CSSM_KEYATTR_PERMANENT) & ~(CSSM_KEYATTR_ALWAYS_SENSITIVE | CSSM_KEYATTR_NEVER_EXTRACTABLE),
187 label)));
188
189 /* Look up unwrapped key in the DLDB. */
190 DbUniqueRecord uniqueId;
191 SSDbCursor dbCursor(ssDb, 1);
192 dbCursor->recordType(recordType());
193 dbCursor->add(CSSM_DB_EQUAL, kInfoKeyLabel, label);
194 CssmClient::Key copiedKey;
195 if (!dbCursor->nextKey(NULL, copiedKey, uniqueId))
196 MacOSError::throwMe(errSecItemNotFound);
197
198 /* Copy the Label, PrintName and ApplicationTag attributes from the old key to the new one. */
199 dbUniqueRecord();
200 DbAttributes oldDbAttributes(mUniqueId->database(), 3);
201 oldDbAttributes.add(kInfoKeyLabel);
202 oldDbAttributes.add(kInfoKeyPrintName);
203 oldDbAttributes.add(kInfoKeyApplicationTag);
204 mUniqueId->get(&oldDbAttributes, NULL);
205 try
206 {
207 uniqueId->modify(recordType(), &oldDbAttributes, NULL, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE);
208 }
209 catch (CssmError e)
210 {
211 // clean up after trying to insert a duplicate key
212 uniqueId->deleteRecord ();
213 throw;
214 }
215
216 /* Set the acl and owner on the unwrapped key. */
217 access->setAccess(*unwrappedKey, maker);
218
219 /* Return a keychain item which represents the new key. */
220 Item item(keychain->item(recordType(), uniqueId));
221
222 KCEventNotifier::PostKeychainEvent(kSecAddEvent, keychain, item);
223
224 return item;
225 }
226
227 Item
228 KeyItem::importTo(const Keychain &keychain, Access *newAccess, SecKeychainAttributeList *attrList)
229 {
230 if (!(keychain->database()->dl()->subserviceMask() & CSSM_SERVICE_CSP))
231 MacOSError::throwMe(errSecInvalidKeychain);
232
233 /* Get the destination keychain's db. */
234 SSDbImpl* dbImpl = dynamic_cast<SSDbImpl*>(&(*keychain->database()));
235 if (dbImpl == NULL)
236 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER);
237
238 SSDb ssDb(dbImpl);
239
240 /* Make sure mKey is valid. */
241 /* We can't call key() here, since we won't have a unique record id yet */
242 if (!mKey)
243 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER);
244
245 // Generate a random label to use initially
246 CssmClient::CSP appleCsp(gGuidAppleCSP);
247 CssmClient::Random random(appleCsp, CSSM_ALGID_APPLE_YARROW);
248 uint8 labelBytes[20];
249 CssmData label(labelBytes, sizeof(labelBytes));
250 random.generate(label, label.Length);
251
252 /* Set up the ACL for the new key. */
253 SecPointer<Access> access;
254 if (newAccess)
255 access = newAccess;
256 else
257 access = new Access(*mKey);
258
259 /* Generate a random 3DES wrapping Key. */
260 CssmClient::GenerateKey genKey(csp(), CSSM_ALGID_3DES_3KEY, 192);
261 CssmClient::Key wrappingKey(genKey(KeySpec(CSSM_KEYUSE_WRAP | CSSM_KEYUSE_UNWRAP,
262 CSSM_KEYATTR_EXTRACTABLE /* | CSSM_KEYATTR_RETURN_DATA */)));
263
264 /* make a random IV */
265 uint8 ivBytes[8];
266 CssmData iv(ivBytes, sizeof(ivBytes));
267 random.generate(iv, iv.length());
268
269 /* Extract the key by wrapping it with the wrapping key. */
270 CssmClient::WrapKey wrap(csp(), CSSM_ALGID_3DES_3KEY_EDE);
271 wrap.key(wrappingKey);
272 wrap.cred(getCredentials(CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED, kSecCredentialTypeDefault));
273 wrap.mode(CSSM_ALGMODE_ECBPad);
274 wrap.padding(CSSM_PADDING_PKCS7);
275 wrap.initVector(iv);
276 CssmClient::Key wrappedKey(wrap(mKey));
277
278 /* Unwrap the new key into the new Keychain. */
279 CssmClient::UnwrapKey unwrap(keychain->csp(), CSSM_ALGID_3DES_3KEY_EDE);
280 unwrap.key(wrappingKey);
281 unwrap.mode(CSSM_ALGMODE_ECBPad);
282 unwrap.padding(CSSM_PADDING_PKCS7);
283 unwrap.initVector(iv);
284
285 /* Setup the dldbHandle in the context. */
286 unwrap.add(CSSM_ATTRIBUTE_DL_DB_HANDLE, ssDb->handle());
287
288 /* Set up an initial aclEntry so we can change it after the unwrap. */
289 Access::Maker maker(Allocator::standard(), Access::Maker::kAnyMakerType);
290 ResourceControlContext rcc;
291 maker.initialOwner(rcc, NULL);
292 unwrap.owner(rcc.input());
293
294 /* Unwrap the key. */
295 uint32 usage = mKey->usage();
296 /* Work around csp brokeness where it sets all usage bits in the Keyheader when CSSM_KEYUSE_ANY is set. */
297 if (usage & CSSM_KEYUSE_ANY)
298 usage = CSSM_KEYUSE_ANY;
299
300 CssmClient::Key unwrappedKey(unwrap(wrappedKey, KeySpec(usage,
301 (mKey->attributes() | CSSM_KEYATTR_PERMANENT) & ~(CSSM_KEYATTR_ALWAYS_SENSITIVE | CSSM_KEYATTR_NEVER_EXTRACTABLE),
302 label)));
303
304 /* Look up unwrapped key in the DLDB. */
305 DbUniqueRecord uniqueId;
306 SSDbCursor dbCursor(ssDb, 1);
307 dbCursor->recordType(recordType());
308 dbCursor->add(CSSM_DB_EQUAL, kInfoKeyLabel, label);
309 CssmClient::Key copiedKey;
310 if (!dbCursor->nextKey(NULL, copiedKey, uniqueId))
311 MacOSError::throwMe(errSecItemNotFound);
312
313 // Set the initial label, application label, and application tag (if provided)
314 if (attrList) {
315 DbAttributes newDbAttributes;
316 SSDbCursor otherDbCursor(ssDb, 1);
317 otherDbCursor->recordType(recordType());
318 bool checkForDuplicates = false;
319
320 for (UInt32 index=0; index < attrList->count; index++) {
321 SecKeychainAttribute attr = attrList->attr[index];
322 CssmData attrData(attr.data, attr.length);
323 if (attr.tag == kSecKeyPrintName) {
324 newDbAttributes.add(kInfoKeyPrintName, attrData);
325 }
326 if (attr.tag == kSecKeyLabel) {
327 newDbAttributes.add(kInfoKeyLabel, attrData);
328 otherDbCursor->add(CSSM_DB_EQUAL, kInfoKeyLabel, attrData);
329 checkForDuplicates = true;
330 }
331 if (attr.tag == kSecKeyApplicationTag) {
332 newDbAttributes.add(kInfoKeyApplicationTag, attrData);
333 otherDbCursor->add(CSSM_DB_EQUAL, kInfoKeyApplicationTag, attrData);
334 checkForDuplicates = true;
335 }
336 }
337
338 DbAttributes otherDbAttributes;
339 DbUniqueRecord otherUniqueId;
340 CssmClient::Key otherKey;
341 try
342 {
343 if (checkForDuplicates && otherDbCursor->nextKey(&otherDbAttributes, otherKey, otherUniqueId))
344 MacOSError::throwMe(errSecDuplicateItem);
345
346 uniqueId->modify(recordType(), &newDbAttributes, NULL, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE);
347 }
348 catch (CssmError e)
349 {
350 // clean up after trying to insert a duplicate key
351 uniqueId->deleteRecord ();
352 throw;
353 }
354 }
355
356 /* Set the acl and owner on the unwrapped key. */
357 access->setAccess(*unwrappedKey, maker);
358
359 /* Return a keychain item which represents the new key. */
360 Item item(keychain->item(recordType(), uniqueId));
361
362 KCEventNotifier::PostKeychainEvent(kSecAddEvent, keychain, item);
363
364 return item;
365 }
366
367 void
368 KeyItem::didModify()
369 {
370 }
371
372 PrimaryKey
373 KeyItem::add(Keychain &keychain)
374 {
375 MacOSError::throwMe(unimpErr);
376 }
377
378 CssmClient::SSDbUniqueRecord
379 KeyItem::ssDbUniqueRecord()
380 {
381 DbUniqueRecordImpl *impl = &*dbUniqueRecord();
382 Security::CssmClient::SSDbUniqueRecordImpl *simpl = dynamic_cast<Security::CssmClient::SSDbUniqueRecordImpl *>(impl);
383 if (simpl == NULL)
384 {
385 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER);
386 }
387
388 return CssmClient::SSDbUniqueRecord(simpl);
389 }
390
391 CssmClient::Key &
392 KeyItem::key()
393 {
394 if (!mKey)
395 {
396 CssmClient::SSDbUniqueRecord uniqueId(ssDbUniqueRecord());
397 CssmDataContainer dataBlob(uniqueId->allocator());
398 uniqueId->get(NULL, &dataBlob);
399 mKey = CssmClient::Key(uniqueId->database()->csp(), *reinterpret_cast<CssmKey *>(dataBlob.Data));
400 }
401
402 return mKey;
403 }
404
405 CssmClient::CSP
406 KeyItem::csp()
407 {
408 return key()->csp();
409 }
410
411
412 const CSSM_X509_ALGORITHM_IDENTIFIER&
413 KeyItem::algorithmIdentifier()
414 {
415 #if 0
416 CssmKey *mKey;
417 CSSM_KEY_TYPE algorithm
418 CSSM_KEY_PTR cssmKey = (CSSM_KEY_PTR)thisData->Data;
419 cssmKey->KeyHeader
420 static void printKeyHeader(
421 const CSSM_KEYHEADER &hdr)
422 {
423 printf(" Algorithm : ");
424 switch(hdr.AlgorithmId) {
425 CSSM_X509_ALGORITHM_IDENTIFIER algID;
426
427 CSSM_OID *CL_algToOid(
428 CSSM_ALGORITHMS algId)
429 typedef struct cssm_x509_algorithm_identifier {
430 CSSM_OID algorithm;
431 CSSM_DATA parameters;
432 } CSSM_X509_ALGORITHM_IDENTIFIER, *CSSM_X509_ALGORITHM_IDENTIFIER_PTR;
433 #endif
434
435 abort();
436 }
437
438 /*
439 * itemID, used to locate Extended Attributes, is the public key hash for keys.
440 */
441 const CssmData &KeyItem::itemID()
442 {
443 if(mPubKeyHash.length() == 0) {
444 /*
445 * Fetch the attribute from disk.
446 */
447 UInt32 tag = kSecKeyLabel;
448 UInt32 format = 0;
449 SecKeychainAttributeInfo attrInfo = {1, &tag, &format};
450 SecKeychainAttributeList *attrList = NULL;
451 getAttributesAndData(&attrInfo, NULL, &attrList, NULL, NULL);
452 if((attrList == NULL) || (attrList->count != 1)) {
453 MacOSError::throwMe(errSecNoSuchAttr);
454 }
455 mPubKeyHash.copy(attrList->attr->data, attrList->attr->length);
456 freeAttributesAndData(attrList, NULL);
457 }
458 return mPubKeyHash;
459 }
460
461
462 unsigned int
463 KeyItem::strengthInBits(const CSSM_X509_ALGORITHM_IDENTIFIER *algid)
464 {
465 // @@@ Make a context with key based on algid and use that to get the effective keysize and not just the logical one.
466 CSSM_KEY_SIZE keySize = {};
467 CSSM_RETURN rv = CSSM_QueryKeySizeInBits (csp()->handle(),
468 CSSM_INVALID_HANDLE,
469 key(),
470 &keySize);
471 if (rv)
472 return 0;
473
474 return keySize.LogicalKeySizeInBits;
475 }
476
477 const AccessCredentials *
478 KeyItem::getCredentials(
479 CSSM_ACL_AUTHORIZATION_TAG operation,
480 SecCredentialType credentialType)
481 {
482 // @@@ Fix this to actually examine the ACL for this key and consider operation and do the right thing.
483 //AutoAclEntryInfoList aclInfos;
484 //key()->getAcl(aclInfos);
485
486 bool smartcard = keychain() != NULL ? (keychain()->database()->dl()->guid() == gGuidAppleSdCSPDL) : false;
487
488 AclFactory factory;
489 switch (credentialType)
490 {
491 case kSecCredentialTypeDefault:
492 return smartcard?globals().smartcardItemCredentials():globals().itemCredentials();
493 case kSecCredentialTypeWithUI:
494 return smartcard?globals().smartcardItemCredentials():factory.promptCred();
495 case kSecCredentialTypeNoUI:
496 return factory.nullCred();
497 default:
498 MacOSError::throwMe(paramErr);
499 }
500 }
501
502 bool
503 KeyItem::operator == (KeyItem &other)
504 {
505 if (mKey && *mKey)
506 {
507 // Pointer compare
508 return this == &other;
509 }
510
511 // If keychains are different, then keys are different
512 Keychain otherKeychain = other.keychain();
513 return (mKeychain && otherKeychain && (*mKeychain == *otherKeychain));
514 }
515
516 void
517 KeyItem::createPair(
518 Keychain keychain,
519 CSSM_ALGORITHMS algorithm,
520 uint32 keySizeInBits,
521 CSSM_CC_HANDLE contextHandle,
522 CSSM_KEYUSE publicKeyUsage,
523 uint32 publicKeyAttr,
524 CSSM_KEYUSE privateKeyUsage,
525 uint32 privateKeyAttr,
526 SecPointer<Access> initialAccess,
527 SecPointer<KeyItem> &outPublicKey,
528 SecPointer<KeyItem> &outPrivateKey)
529 {
530 bool freeKeys = false;
531 bool deleteContext = false;
532
533 if (!(keychain->database()->dl()->subserviceMask() & CSSM_SERVICE_CSP))
534 MacOSError::throwMe(errSecInvalidKeychain);
535
536 SSDbImpl* impl = dynamic_cast<SSDbImpl*>(&(*keychain->database()));
537 if (impl == NULL)
538 {
539 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER);
540 }
541
542 SSDb ssDb(impl);
543 CssmClient::CSP csp(keychain->csp());
544 CssmClient::CSP appleCsp(gGuidAppleCSP);
545
546 // Generate a random label to use initially
547 CssmClient::Random random(appleCsp, CSSM_ALGID_APPLE_YARROW);
548 uint8 labelBytes[20];
549 CssmData label(labelBytes, sizeof(labelBytes));
550 random.generate(label, label.Length);
551
552 // Create a Access::Maker for the initial owner of the private key.
553 ResourceControlContext rcc;
554 memset(&rcc, 0, sizeof(rcc));
555 Access::Maker maker;
556 // @@@ 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.
557 maker.initialOwner(rcc);
558 // Create the cred we need to manipulate the keys until we actually set a new access control for them.
559 const AccessCredentials *cred = maker.cred();
560
561 CSSM_KEY publicCssmKey, privateCssmKey;
562 memset(&publicCssmKey, 0, sizeof(publicCssmKey));
563 memset(&privateCssmKey, 0, sizeof(privateCssmKey));
564
565 CSSM_CC_HANDLE ccHandle = 0;
566
567 Item publicKeyItem, privateKeyItem;
568 try
569 {
570 CSSM_RETURN status;
571 if (contextHandle)
572 ccHandle = contextHandle;
573 else
574 {
575 status = CSSM_CSP_CreateKeyGenContext(csp->handle(), algorithm, keySizeInBits, NULL, NULL, NULL, NULL, NULL, &ccHandle);
576 if (status)
577 CssmError::throwMe(status);
578 deleteContext = true;
579 }
580
581 CSSM_DL_DB_HANDLE dldbHandle = ssDb->handle();
582 CSSM_DL_DB_HANDLE_PTR dldbHandlePtr = &dldbHandle;
583 CSSM_CONTEXT_ATTRIBUTE contextAttributes = { CSSM_ATTRIBUTE_DL_DB_HANDLE, sizeof(dldbHandle), { (char *)dldbHandlePtr } };
584 status = CSSM_UpdateContextAttributes(ccHandle, 1, &contextAttributes);
585 if (status)
586 CssmError::throwMe(status);
587
588 // Generate the keypair
589 status = CSSM_GenerateKeyPair(ccHandle, publicKeyUsage, publicKeyAttr, &label, &publicCssmKey, privateKeyUsage, privateKeyAttr, &label, &rcc, &privateCssmKey);
590 if (status)
591 CssmError::throwMe(status);
592 freeKeys = true;
593
594 // Find the keys we just generated in the DL to get SecKeyRef's to them
595 // so we can change the label to be the hash of the public key, and
596 // fix up other attributes.
597
598 // Look up public key in the DLDB.
599 DbAttributes pubDbAttributes;
600 DbUniqueRecord pubUniqueId;
601 SSDbCursor dbPubCursor(ssDb, 1);
602 dbPubCursor->recordType(CSSM_DL_DB_RECORD_PUBLIC_KEY);
603 dbPubCursor->add(CSSM_DB_EQUAL, kInfoKeyLabel, label);
604 CssmClient::Key publicKey;
605 if (!dbPubCursor->nextKey(&pubDbAttributes, publicKey, pubUniqueId))
606 MacOSError::throwMe(errSecItemNotFound);
607
608 // Look up private key in the DLDB.
609 DbAttributes privDbAttributes;
610 DbUniqueRecord privUniqueId;
611 SSDbCursor dbPrivCursor(ssDb, 1);
612 dbPrivCursor->recordType(CSSM_DL_DB_RECORD_PRIVATE_KEY);
613 dbPrivCursor->add(CSSM_DB_EQUAL, kInfoKeyLabel, label);
614 CssmClient::Key privateKey;
615 if (!dbPrivCursor->nextKey(&privDbAttributes, privateKey, privUniqueId))
616 MacOSError::throwMe(errSecItemNotFound);
617
618 // Convert reference public key to a raw key so we can use it
619 // in the appleCsp.
620 CssmClient::WrapKey wrap(csp, CSSM_ALGID_NONE);
621 wrap.cred(cred);
622 CssmClient::Key rawPubKey = wrap(publicKey);
623
624 // Calculate the hash of the public key using the appleCSP.
625 CssmClient::PassThrough passThrough(appleCsp);
626 void *outData;
627 CssmData *cssmData;
628
629 /* Given a CSSM_KEY_PTR in any format, obtain the SHA-1 hash of the
630 * associated key blob.
631 * Key is specified in CSSM_CSP_CreatePassThroughContext.
632 * Hash is allocated bythe CSP, in the App's memory, and returned
633 * in *outData. */
634 passThrough.key(rawPubKey);
635 passThrough(CSSM_APPLECSP_KEYDIGEST, NULL, &outData);
636 cssmData = reinterpret_cast<CssmData *>(outData);
637 CssmData &pubKeyHash = *cssmData;
638
639 auto_ptr<string>privDescription;
640 auto_ptr<string>pubDescription;
641 try {
642 privDescription.reset(new string(initialAccess->promptDescription()));
643 pubDescription.reset(new string(initialAccess->promptDescription()));
644 }
645 catch(...) {
646 /* this path taken if no promptDescription available, e.g., for complex ACLs */
647 privDescription.reset(new string("Private key"));
648 pubDescription.reset(new string("Public key"));
649 }
650
651 // Set the label of the public key to the public key hash.
652 // Set the PrintName of the public key to the description in the acl.
653 pubDbAttributes.add(kInfoKeyLabel, pubKeyHash);
654 pubDbAttributes.add(kInfoKeyPrintName, *pubDescription);
655 pubUniqueId->modify(CSSM_DL_DB_RECORD_PUBLIC_KEY, &pubDbAttributes, NULL, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE);
656
657 // Set the label of the private key to the public key hash.
658 // Set the PrintName of the private key to the description in the acl.
659 privDbAttributes.add(kInfoKeyLabel, pubKeyHash);
660 privDbAttributes.add(kInfoKeyPrintName, *privDescription);
661 privUniqueId->modify(CSSM_DL_DB_RECORD_PRIVATE_KEY, &privDbAttributes, NULL, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE);
662
663 // @@@ Not exception safe!
664 csp.allocator().free(cssmData->Data);
665 csp.allocator().free(cssmData);
666
667 // Finally fix the acl and owner of the private key to the specified access control settings.
668 initialAccess->setAccess(*privateKey, maker);
669
670 if(publicKeyAttr & CSSM_KEYATTR_PUBLIC_KEY_ENCRYPT) {
671 /*
672 * Make the public key acl completely open.
673 * If the key was not encrypted, it already has a wide-open
674 * ACL (though that is a feature of securityd; it's not
675 * CDSA-specified behavior).
676 */
677 SecPointer<Access> pubKeyAccess(new Access());
678 pubKeyAccess->setAccess(*publicKey, maker);
679 }
680
681 // Create keychain items which will represent the keys.
682 publicKeyItem = keychain->item(CSSM_DL_DB_RECORD_PUBLIC_KEY, pubUniqueId);
683 privateKeyItem = keychain->item(CSSM_DL_DB_RECORD_PRIVATE_KEY, privUniqueId);
684
685 KeyItem* impl = dynamic_cast<KeyItem*>(&(*publicKeyItem));
686 if (impl == NULL)
687 {
688 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER);
689 }
690
691 outPublicKey = impl;
692
693 impl = dynamic_cast<KeyItem*>(&(*privateKeyItem));
694 if (impl == NULL)
695 {
696 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER);
697 }
698
699 outPrivateKey = impl;
700 }
701 catch (...)
702 {
703 if (freeKeys)
704 {
705 // Delete the keys if something goes wrong so we don't end up with inaccessible keys in the database.
706 CSSM_FreeKey(csp->handle(), cred, &publicCssmKey, TRUE);
707 CSSM_FreeKey(csp->handle(), cred, &privateCssmKey, TRUE);
708 }
709
710 if (deleteContext)
711 CSSM_DeleteContext(ccHandle);
712
713 throw;
714 }
715
716 if (freeKeys)
717 {
718 CSSM_FreeKey(csp->handle(), NULL, &publicCssmKey, FALSE);
719 CSSM_FreeKey(csp->handle(), NULL, &privateCssmKey, FALSE);
720 }
721
722 if (deleteContext)
723 CSSM_DeleteContext(ccHandle);
724
725 if (keychain && publicKeyItem && privateKeyItem)
726 {
727 keychain->postEvent(kSecAddEvent, publicKeyItem);
728 keychain->postEvent(kSecAddEvent, privateKeyItem);
729 }
730 }
731
732 void
733 KeyItem::importPair(
734 Keychain keychain,
735 const CSSM_KEY &publicWrappedKey,
736 const CSSM_KEY &privateWrappedKey,
737 SecPointer<Access> initialAccess,
738 SecPointer<KeyItem> &outPublicKey,
739 SecPointer<KeyItem> &outPrivateKey)
740 {
741 bool freePublicKey = false;
742 bool freePrivateKey = false;
743 bool deleteContext = false;
744
745 if (!(keychain->database()->dl()->subserviceMask() & CSSM_SERVICE_CSP))
746 MacOSError::throwMe(errSecInvalidKeychain);
747
748 SSDbImpl* impl = dynamic_cast<SSDbImpl *>(&(*keychain->database()));
749 if (impl == NULL)
750 {
751 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER);
752 }
753
754 SSDb ssDb(impl);
755 CssmClient::CSP csp(keychain->csp());
756 CssmClient::CSP appleCsp(gGuidAppleCSP);
757
758 // Create a Access::Maker for the initial owner of the private key.
759 ResourceControlContext rcc;
760 memset(&rcc, 0, sizeof(rcc));
761 Access::Maker maker(Allocator::standard(), Access::Maker::kAnyMakerType);
762 // @@@ Potentially provide a credential argument which allows us to unwrap keys in the csp.
763 // Currently the CSP lets anyone do this, but we might restrict this in the future, e.g.
764 // a smartcard could require out of band pin entry before a key can be generated.
765 maker.initialOwner(rcc);
766 // Create the cred we need to manipulate the keys until we actually set a new access control for them.
767 const AccessCredentials *cred = maker.cred();
768
769 CSSM_KEY publicCssmKey, privateCssmKey;
770 memset(&publicCssmKey, 0, sizeof(publicCssmKey));
771 memset(&privateCssmKey, 0, sizeof(privateCssmKey));
772
773 CSSM_CC_HANDLE ccHandle = 0;
774
775 Item publicKeyItem, privateKeyItem;
776 try
777 {
778 CSSM_RETURN status;
779
780 // Calculate the hash of the public key using the appleCSP.
781 CssmClient::PassThrough passThrough(appleCsp);
782 void *outData;
783 CssmData *cssmData;
784
785 /* Given a CSSM_KEY_PTR in any format, obtain the SHA-1 hash of the
786 * associated key blob.
787 * Key is specified in CSSM_CSP_CreatePassThroughContext.
788 * Hash is allocated bythe CSP, in the App's memory, and returned
789 * in *outData. */
790 passThrough.key(&publicWrappedKey);
791 passThrough(CSSM_APPLECSP_KEYDIGEST, NULL, &outData);
792 cssmData = reinterpret_cast<CssmData *>(outData);
793 CssmData &pubKeyHash = *cssmData;
794
795 status = CSSM_CSP_CreateSymmetricContext(csp->handle(), publicWrappedKey.KeyHeader.WrapAlgorithmId, CSSM_ALGMODE_NONE, NULL, NULL, NULL, CSSM_PADDING_NONE, NULL, &ccHandle);
796 if (status)
797 CssmError::throwMe(status);
798 deleteContext = true;
799
800 CSSM_DL_DB_HANDLE dldbHandle = ssDb->handle();
801 CSSM_DL_DB_HANDLE_PTR dldbHandlePtr = &dldbHandle;
802 CSSM_CONTEXT_ATTRIBUTE contextAttributes = { CSSM_ATTRIBUTE_DL_DB_HANDLE, sizeof(dldbHandle), { (char *)dldbHandlePtr } };
803 status = CSSM_UpdateContextAttributes(ccHandle, 1, &contextAttributes);
804 if (status)
805 CssmError::throwMe(status);
806
807 // Unwrap the the keys
808 CSSM_DATA descriptiveData = {0, NULL};
809
810 status = CSSM_UnwrapKey(
811 ccHandle,
812 NULL,
813 &publicWrappedKey,
814 publicWrappedKey.KeyHeader.KeyUsage,
815 publicWrappedKey.KeyHeader.KeyAttr | CSSM_KEYATTR_PERMANENT,
816 &pubKeyHash,
817 &rcc,
818 &publicCssmKey,
819 &descriptiveData);
820
821 if (status)
822 CssmError::throwMe(status);
823 freePublicKey = true;
824
825 if (descriptiveData.Data != NULL)
826 free (descriptiveData.Data);
827
828 status = CSSM_UnwrapKey(
829 ccHandle,
830 NULL,
831 &privateWrappedKey,
832 privateWrappedKey.KeyHeader.KeyUsage,
833 privateWrappedKey.KeyHeader.KeyAttr | CSSM_KEYATTR_PERMANENT,
834 &pubKeyHash,
835 &rcc,
836 &privateCssmKey,
837 &descriptiveData);
838
839 if (status)
840 CssmError::throwMe(status);
841
842 if (descriptiveData.Data != NULL)
843 free (descriptiveData.Data);
844
845 freePrivateKey = true;
846
847 // Find the keys we just generated in the DL to get SecKeyRefs to them
848 // so we can change the label to be the hash of the public key, and
849 // fix up other attributes.
850
851 // Look up public key in the DLDB.
852 DbAttributes pubDbAttributes;
853 DbUniqueRecord pubUniqueId;
854 SSDbCursor dbPubCursor(ssDb, 1);
855 dbPubCursor->recordType(CSSM_DL_DB_RECORD_PUBLIC_KEY);
856 dbPubCursor->add(CSSM_DB_EQUAL, kInfoKeyLabel, pubKeyHash);
857 CssmClient::Key publicKey;
858 if (!dbPubCursor->nextKey(&pubDbAttributes, publicKey, pubUniqueId))
859 MacOSError::throwMe(errSecItemNotFound);
860
861 // Look up private key in the DLDB.
862 DbAttributes privDbAttributes;
863 DbUniqueRecord privUniqueId;
864 SSDbCursor dbPrivCursor(ssDb, 1);
865 dbPrivCursor->recordType(CSSM_DL_DB_RECORD_PRIVATE_KEY);
866 dbPrivCursor->add(CSSM_DB_EQUAL, kInfoKeyLabel, pubKeyHash);
867 CssmClient::Key privateKey;
868 if (!dbPrivCursor->nextKey(&privDbAttributes, privateKey, privUniqueId))
869 MacOSError::throwMe(errSecItemNotFound);
870
871 // @@@ Not exception safe!
872 csp.allocator().free(cssmData->Data);
873 csp.allocator().free(cssmData);
874
875 auto_ptr<string>privDescription;
876 auto_ptr<string>pubDescription;
877 try {
878 privDescription.reset(new string(initialAccess->promptDescription()));
879 pubDescription.reset(new string(initialAccess->promptDescription()));
880 }
881 catch(...) {
882 /* this path taken if no promptDescription available, e.g., for complex ACLs */
883 privDescription.reset(new string("Private key"));
884 pubDescription.reset(new string("Public key"));
885 }
886
887 // Set the label of the public key to the public key hash.
888 // Set the PrintName of the public key to the description in the acl.
889 pubDbAttributes.add(kInfoKeyPrintName, *pubDescription);
890 pubUniqueId->modify(CSSM_DL_DB_RECORD_PUBLIC_KEY, &pubDbAttributes, NULL, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE);
891
892 // Set the label of the private key to the public key hash.
893 // Set the PrintName of the private key to the description in the acl.
894 privDbAttributes.add(kInfoKeyPrintName, *privDescription);
895 privUniqueId->modify(CSSM_DL_DB_RECORD_PRIVATE_KEY, &privDbAttributes, NULL, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE);
896
897 // Finally fix the acl and owner of the private key to the specified access control settings.
898 initialAccess->setAccess(*privateKey, maker);
899
900 // Make the public key acl completely open
901 SecPointer<Access> pubKeyAccess(new Access());
902 pubKeyAccess->setAccess(*publicKey, maker);
903
904 // Create keychain items which will represent the keys.
905 publicKeyItem = keychain->item(CSSM_DL_DB_RECORD_PUBLIC_KEY, pubUniqueId);
906 privateKeyItem = keychain->item(CSSM_DL_DB_RECORD_PRIVATE_KEY, privUniqueId);
907
908 KeyItem* impl = dynamic_cast<KeyItem*>(&(*publicKeyItem));
909 if (impl == NULL)
910 {
911 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER);
912 }
913
914 outPublicKey = impl;
915
916 impl = dynamic_cast<KeyItem*>(&(*privateKeyItem));
917 if (impl == NULL)
918 {
919 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER);
920 }
921 outPrivateKey = impl;
922 }
923 catch (...)
924 {
925 if (freePublicKey)
926 CSSM_FreeKey(csp->handle(), cred, &publicCssmKey, TRUE);
927 if (freePrivateKey)
928 CSSM_FreeKey(csp->handle(), cred, &privateCssmKey, TRUE);
929
930 if (deleteContext)
931 CSSM_DeleteContext(ccHandle);
932
933 throw;
934 }
935
936 if (freePublicKey)
937 CSSM_FreeKey(csp->handle(), cred, &publicCssmKey, FALSE);
938 if (freePrivateKey)
939 CSSM_FreeKey(csp->handle(), cred, &privateCssmKey, FALSE);
940
941 if (deleteContext)
942 CSSM_DeleteContext(ccHandle);
943
944 if (keychain && publicKeyItem && privateKeyItem)
945 {
946 KCEventNotifier::PostKeychainEvent(kSecAddEvent, keychain, publicKeyItem);
947 KCEventNotifier::PostKeychainEvent(kSecAddEvent, keychain, privateKeyItem);
948 }
949 }
950
951 SecPointer<KeyItem>
952 KeyItem::generateWithAttributes(const SecKeychainAttributeList *attrList,
953 Keychain keychain,
954 CSSM_ALGORITHMS algorithm,
955 uint32 keySizeInBits,
956 CSSM_CC_HANDLE contextHandle,
957 CSSM_KEYUSE keyUsage,
958 uint32 keyAttr,
959 SecPointer<Access> initialAccess)
960 {
961 CssmClient::CSP appleCsp(gGuidAppleCSP);
962 CssmClient::CSP csp(NULL);
963 SSDb ssDb(NULL);
964 uint8 labelBytes[20];
965 CssmData label(labelBytes, sizeof(labelBytes));
966 bool freeKey = false;
967 bool deleteContext = false;
968 const CSSM_DATA *plabel = NULL;
969
970 if (keychain)
971 {
972 if (!(keychain->database()->dl()->subserviceMask() & CSSM_SERVICE_CSP))
973 MacOSError::throwMe(errSecInvalidKeychain);
974
975 SSDbImpl* impl = dynamic_cast<SSDbImpl *>(&(*keychain->database()));
976 if (impl == NULL)
977 {
978 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER);
979 }
980
981 ssDb = SSDb(impl);
982 csp = keychain->csp();
983
984 // Generate a random label to use initially
985 CssmClient::Random random(appleCsp, CSSM_ALGID_APPLE_YARROW);
986 random.generate(label, label.Length);
987 plabel = &label;
988 }
989 else
990 {
991 // Not a persistent key so create it in the regular csp
992 csp = appleCsp;
993 }
994
995 // Create a Access::Maker for the initial owner of the private key.
996 ResourceControlContext *prcc = NULL, rcc;
997 const AccessCredentials *cred = NULL;
998 Access::Maker maker;
999 if (keychain && initialAccess)
1000 {
1001 memset(&rcc, 0, sizeof(rcc));
1002 // @@@ Potentially provide a credential argument which allows us to generate keys in the csp.
1003 // Currently the CSP lets anyone do this, but we might restrict this in the future, e.g. a smartcard
1004 // could require out-of-band pin entry before a key can be generated.
1005 maker.initialOwner(rcc);
1006 // Create the cred we need to manipulate the keys until we actually set a new access control for them.
1007 cred = maker.cred();
1008 prcc = &rcc;
1009 }
1010
1011 CSSM_KEY cssmKey;
1012
1013 CSSM_CC_HANDLE ccHandle = 0;
1014
1015 Item keyItem;
1016 try
1017 {
1018 CSSM_RETURN status;
1019 if (contextHandle)
1020 ccHandle = contextHandle;
1021 else
1022 {
1023 status = CSSM_CSP_CreateKeyGenContext(csp->handle(), algorithm, keySizeInBits, NULL, NULL, NULL, NULL, NULL, &ccHandle);
1024 if (status)
1025 CssmError::throwMe(status);
1026 deleteContext = true;
1027 }
1028
1029 if (ssDb)
1030 {
1031 CSSM_DL_DB_HANDLE dldbHandle = ssDb->handle();
1032 CSSM_DL_DB_HANDLE_PTR dldbHandlePtr = &dldbHandle;
1033 CSSM_CONTEXT_ATTRIBUTE contextAttributes = { CSSM_ATTRIBUTE_DL_DB_HANDLE, sizeof(dldbHandle), { (char *)dldbHandlePtr } };
1034 status = CSSM_UpdateContextAttributes(ccHandle, 1, &contextAttributes);
1035 if (status)
1036 CssmError::throwMe(status);
1037
1038 keyAttr |= CSSM_KEYATTR_PERMANENT;
1039 }
1040
1041 // Generate the key
1042 status = CSSM_GenerateKey(ccHandle, keyUsage, keyAttr, plabel, prcc, &cssmKey);
1043 if (status)
1044 CssmError::throwMe(status);
1045
1046 if (ssDb)
1047 {
1048 freeKey = true;
1049 // Find the key we just generated in the DL and get a SecKeyRef
1050 // so we can specify the label attribute(s) and initial ACL.
1051
1052 // Look up key in the DLDB.
1053 DbAttributes dbAttributes;
1054 DbUniqueRecord uniqueId;
1055 SSDbCursor dbCursor(ssDb, 1);
1056 dbCursor->recordType(CSSM_DL_DB_RECORD_SYMMETRIC_KEY);
1057 dbCursor->add(CSSM_DB_EQUAL, kInfoKeyLabel, label);
1058 CssmClient::Key key;
1059 if (!dbCursor->nextKey(&dbAttributes, key, uniqueId))
1060 MacOSError::throwMe(errSecItemNotFound);
1061
1062 // Set the initial label, application label, and application tag (if provided)
1063 if (attrList) {
1064 DbAttributes newDbAttributes;
1065 SSDbCursor otherDbCursor(ssDb, 1);
1066 otherDbCursor->recordType(CSSM_DL_DB_RECORD_SYMMETRIC_KEY);
1067 bool checkForDuplicates = false;
1068
1069 for (UInt32 index=0; index < attrList->count; index++) {
1070 SecKeychainAttribute attr = attrList->attr[index];
1071 CssmData attrData(attr.data, attr.length);
1072 if (attr.tag == kSecKeyPrintName) {
1073 newDbAttributes.add(kInfoKeyPrintName, attrData);
1074 }
1075 if (attr.tag == kSecKeyLabel) {
1076 newDbAttributes.add(kInfoKeyLabel, attrData);
1077 otherDbCursor->add(CSSM_DB_EQUAL, kInfoKeyLabel, attrData);
1078 checkForDuplicates = true;
1079 }
1080 if (attr.tag == kSecKeyApplicationTag) {
1081 newDbAttributes.add(kInfoKeyApplicationTag, attrData);
1082 otherDbCursor->add(CSSM_DB_EQUAL, kInfoKeyApplicationTag, attrData);
1083 checkForDuplicates = true;
1084 }
1085 }
1086
1087 DbAttributes otherDbAttributes;
1088 DbUniqueRecord otherUniqueId;
1089 CssmClient::Key otherKey;
1090 if (checkForDuplicates && otherDbCursor->nextKey(&otherDbAttributes, otherKey, otherUniqueId))
1091 MacOSError::throwMe(errSecDuplicateItem);
1092
1093 uniqueId->modify(CSSM_DL_DB_RECORD_SYMMETRIC_KEY, &newDbAttributes, NULL, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE);
1094 }
1095
1096 // Finally, fix the acl and owner of the key to the specified access control settings.
1097 if (initialAccess)
1098 initialAccess->setAccess(*key, maker);
1099
1100 // Create keychain item which will represent the key.
1101 keyItem = keychain->item(CSSM_DL_DB_RECORD_SYMMETRIC_KEY, uniqueId);
1102 }
1103 else
1104 {
1105 CssmClient::Key tempKey(csp, cssmKey);
1106 keyItem = new KeyItem(tempKey);
1107 }
1108 }
1109 catch (...)
1110 {
1111 if (freeKey)
1112 {
1113 // Delete the key if something goes wrong so we don't end up with inaccessible keys in the database.
1114 CSSM_FreeKey(csp->handle(), cred, &cssmKey, TRUE);
1115 }
1116
1117 if (deleteContext)
1118 CSSM_DeleteContext(ccHandle);
1119
1120 throw;
1121 }
1122
1123 if (freeKey)
1124 {
1125 CSSM_FreeKey(csp->handle(), NULL, &cssmKey, FALSE);
1126 }
1127
1128 if (deleteContext)
1129 CSSM_DeleteContext(ccHandle);
1130
1131 if (keychain && keyItem)
1132 keychain->postEvent(kSecAddEvent, keyItem);
1133
1134 KeyItem* item = dynamic_cast<KeyItem*>(&*keyItem);
1135 if (item == NULL)
1136 {
1137 CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER);
1138 }
1139
1140 return item;
1141 }
1142
1143 SecPointer<KeyItem>
1144 KeyItem::generate(Keychain keychain,
1145 CSSM_ALGORITHMS algorithm,
1146 uint32 keySizeInBits,
1147 CSSM_CC_HANDLE contextHandle,
1148 CSSM_KEYUSE keyUsage,
1149 uint32 keyAttr,
1150 SecPointer<Access> initialAccess)
1151 {
1152 return KeyItem::generateWithAttributes(NULL, keychain,
1153 algorithm, keySizeInBits, contextHandle,
1154 keyUsage, keyAttr, initialAccess);
1155 }
1156
1157
1158 void KeyItem::RawSign(SecPadding padding, CSSM_DATA dataToSign, const AccessCredentials *credentials, CSSM_DATA& signature)
1159 {
1160 CSSM_ALGORITHMS baseAlg = key()->header().algorithm();
1161 if ((baseAlg != CSSM_ALGID_RSA) && (baseAlg != CSSM_ALGID_ECDSA))
1162 {
1163 MacOSError::throwMe(paramErr);
1164 }
1165
1166 CSSM_ALGORITHMS paddingAlg = CSSM_PADDING_PKCS1;
1167
1168 switch (padding)
1169 {
1170 case kSecPaddingPKCS1:
1171 {
1172 paddingAlg = CSSM_PADDING_PKCS1;
1173 break;
1174 }
1175
1176 case kSecPaddingPKCS1MD2:
1177 {
1178 baseAlg = CSSM_ALGID_MD2WithRSA;
1179 break;
1180 }
1181
1182 case kSecPaddingPKCS1MD5:
1183 {
1184 baseAlg = CSSM_ALGID_MD5WithRSA;
1185 break;
1186 }
1187
1188 case kSecPaddingPKCS1SHA1:
1189 {
1190 baseAlg = CSSM_ALGID_SHA1WithRSA;
1191 break;
1192 }
1193
1194 default:
1195 {
1196 paddingAlg = CSSM_PADDING_NONE;
1197 break;
1198 }
1199 }
1200
1201 Sign signContext(csp(), baseAlg);
1202 signContext.key(key());
1203 signContext.set(CSSM_ATTRIBUTE_PADDING, paddingAlg);
1204 signContext.cred(credentials);
1205
1206 CssmData data(dataToSign.Data, dataToSign.Length);
1207 signContext.sign(data);
1208
1209 CssmData sig(signature.Data, signature.Length);
1210 signContext(sig); // yes, this is an accessor. Believe it, or not.
1211 signature.Length = sig.length();
1212 }
1213
1214
1215
1216 void KeyItem::RawVerify(SecPadding padding, CSSM_DATA dataToVerify, const AccessCredentials *credentials, CSSM_DATA sig)
1217 {
1218 CSSM_ALGORITHMS baseAlg = key()->header().algorithm();
1219 if ((baseAlg != CSSM_ALGID_RSA) && (baseAlg != CSSM_ALGID_ECDSA))
1220 {
1221 MacOSError::throwMe(paramErr);
1222 }
1223
1224 CSSM_ALGORITHMS paddingAlg = CSSM_PADDING_PKCS1;
1225
1226 switch (padding)
1227 {
1228 case kSecPaddingPKCS1:
1229 {
1230 paddingAlg = CSSM_PADDING_PKCS1;
1231 break;
1232 }
1233
1234 case kSecPaddingPKCS1MD2:
1235 {
1236 baseAlg = CSSM_ALGID_MD2WithRSA;
1237 break;
1238 }
1239
1240 case kSecPaddingPKCS1MD5:
1241 {
1242 baseAlg = CSSM_ALGID_MD5WithRSA;
1243 break;
1244 }
1245
1246 case kSecPaddingPKCS1SHA1:
1247 {
1248 baseAlg = CSSM_ALGID_SHA1WithRSA;
1249 break;
1250 }
1251
1252 default:
1253 {
1254 paddingAlg = CSSM_PADDING_NONE;
1255 break;
1256 }
1257 }
1258
1259 Verify verifyContext(csp(), baseAlg);
1260 verifyContext.key(key());
1261 verifyContext.set(CSSM_ATTRIBUTE_PADDING, paddingAlg);
1262 verifyContext.cred(credentials);
1263
1264 CssmData data(dataToVerify.Data, dataToVerify.Length);
1265 CssmData signature(sig.Data, sig.Length);
1266 verifyContext.verify(data, signature);
1267 }
1268
1269
1270
1271 void KeyItem::Encrypt(SecPadding padding, CSSM_DATA dataToEncrypt, const AccessCredentials *credentials, CSSM_DATA& encryptedData)
1272 {
1273 CSSM_ALGORITHMS baseAlg = key()->header().algorithm();
1274 if (baseAlg != CSSM_ALGID_RSA)
1275 {
1276 MacOSError::throwMe(paramErr);
1277 }
1278
1279 CSSM_ALGORITHMS paddingAlg = CSSM_PADDING_PKCS1;
1280
1281 switch (padding)
1282 {
1283 case kSecPaddingPKCS1:
1284 {
1285 paddingAlg = CSSM_PADDING_PKCS1;
1286 break;
1287 }
1288
1289 default:
1290 {
1291 paddingAlg = CSSM_PADDING_NONE;
1292 break;
1293 }
1294 }
1295
1296 CssmClient::Encrypt encryptContext(csp(), baseAlg);
1297 encryptContext.key(key());
1298 encryptContext.padding(paddingAlg);
1299 encryptContext.cred(credentials);
1300
1301 CssmData inData(dataToEncrypt.Data, dataToEncrypt.Length);
1302 CssmData outData(encryptedData.Data, encryptedData.Length);
1303 CssmData remData((void*) NULL, 0);
1304
1305 encryptedData.Length = encryptContext.encrypt(inData, outData, remData);
1306 }
1307
1308
1309
1310 void KeyItem::Decrypt(SecPadding padding, CSSM_DATA dataToDecrypt, const AccessCredentials *credentials, CSSM_DATA& decryptedData)
1311 {
1312 CSSM_ALGORITHMS baseAlg = key()->header().algorithm();
1313 if (baseAlg != CSSM_ALGID_RSA)
1314 {
1315 MacOSError::throwMe(paramErr);
1316 }
1317
1318 CSSM_ALGORITHMS paddingAlg = CSSM_PADDING_PKCS1;
1319
1320 switch (padding)
1321 {
1322 case kSecPaddingPKCS1:
1323 {
1324 paddingAlg = CSSM_PADDING_PKCS1;
1325 break;
1326 }
1327
1328
1329 default:
1330 {
1331 paddingAlg = CSSM_PADDING_NONE;
1332 break;
1333 }
1334 }
1335
1336 CssmClient::Decrypt decryptContext(csp(), baseAlg);
1337 decryptContext.key(key());
1338 decryptContext.padding(paddingAlg);
1339 decryptContext.cred(credentials);
1340
1341 CssmData inData(dataToDecrypt.Data, dataToDecrypt.Length);
1342 CssmData outData(decryptedData.Data, decryptedData.Length);
1343 CssmData remData((void*) NULL, 0);
1344 decryptedData.Length = decryptContext.decrypt(inData, outData, remData);
1345 if (remData.Data != NULL)
1346 {
1347 free(remData.Data);
1348 }
1349 }
1350