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