1/* 2 * Copyright (c) 2004,2011,2013-2014 Apple 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 * SecImportExportAgg.cpp - private routines used by SecImportExport.h for 24 * aggregate (PKCS12 and PKCS7) conversion. 25 */ 26 27#include "SecImportExportAgg.h" 28#include "SecExternalRep.h" 29#include "SecImportExportUtils.h" 30#include "SecNetscapeTemplates.h" 31#include "Certificate.h" 32#include <security_pkcs12/SecPkcs12.h> 33#include <Security/SecBase.h> 34#include <Security/SecCmsDecoder.h> 35#include <Security/SecCmsEncoder.h> 36#include <Security/SecCmsMessage.h> 37#include <Security/SecCmsContentInfo.h> 38#include <Security/SecCmsSignedData.h> 39#include <security_asn1/SecNssCoder.h> 40#include <security_asn1/nssUtils.h> 41#include <security_cdsa_utils/cuCdsaUtils.h> 42#include <security_keychain/Globals.h> 43#include <Security/SecIdentityPriv.h> 44#include <Security/SecKeyPriv.h> 45 46using namespace Security; 47using namespace KeychainCore; 48 49#pragma mark --- Aggregate Export routines --- 50 51OSStatus impExpPkcs12Export( 52 CFArrayRef exportReps, // SecExportReps 53 SecItemImportExportFlags flags, // kSecItemPemArmour, etc. 54 const SecKeyImportExportParameters *keyParams, // optional 55 CFMutableDataRef outData) // output appended here 56{ 57 SecPkcs12CoderRef p12Coder; 58 OSStatus ortn = errSecSuccess; 59 CFMutableArrayRef exportItems; // SecKeychainItemRefs 60 CFDataRef tmpData = NULL; 61 CSSM_CSP_HANDLE cspHand; 62 CSSM_KEY *passKey = NULL; 63 CFStringRef phraseStr = NULL; 64 65 if( (keyParams == NULL) || 66 ( (keyParams->passphrase == NULL) && 67 !(keyParams->flags & kSecKeySecurePassphrase) ) ) { 68 /* passphrase mandatory */ 69 return errSecPassphraseRequired; 70 } 71 CFIndex numReps = CFArrayGetCount(exportReps); 72 if(numReps == 0) { 73 SecImpExpDbg("impExpPkcs12Export: no items to export"); 74 return errSecItemNotFound; 75 } 76 77 /* 78 * Build an array of SecKeychainItemRefs. 79 * 80 * Keychain is inferred from the objects to be exported. Some may be 81 * floating certs with no keychain. 82 */ 83 exportItems = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 84 SecKeychainRef kcRef = nil; 85 for(CFIndex dex=0; dex<numReps; dex++) { 86 SecExportRep *exportRep = 87 (SecExportRep *)CFArrayGetValueAtIndex(exportReps, dex); 88 SecKeychainItemRef kcItemRef = (SecKeychainItemRef)exportRep->kcItem(); 89 CFArrayAppendValue(exportItems, kcItemRef); 90 if(kcRef == nil) { 91 SecKeychainItemCopyKeychain(kcItemRef, &kcRef); 92 /* ignore error - we do this 'til we get a kcRef */ 93 } 94 } 95 96 /* Set up a PKCS12 encoder */ 97 ortn = SecPkcs12CoderCreate(&p12Coder); 98 if(ortn) { 99 return ortn; 100 } 101 /* subsequent errors to errOut: */ 102 103 ortn = SecPkcs12SetKeychain(p12Coder, kcRef); 104 if(ortn) { 105 goto errOut; 106 } 107 108 /* We need a CSPDL handle for possible secure passphrase acquisition */ 109 ortn = SecKeychainGetCSPHandle(kcRef, &cspHand); 110 if(ortn) { 111 SecImpExpDbg("SecKeychainGetCSPHandle error"); 112 goto errOut; 113 } 114 115 /* explicit passphrase, or get one ourself? */ 116 ortn = impExpPassphraseCommon(keyParams, cspHand, SPF_String, 117 VP_Export, (CFTypeRef *)&phraseStr, &passKey); 118 if(ortn) { 119 goto errOut; 120 } 121 if(phraseStr != NULL) { 122 ortn = SecPkcs12SetMACPassphrase(p12Coder, phraseStr); 123 CFRelease(phraseStr); 124 if(ortn) { 125 SecImpExpDbg("SecPkcs12SetMACPassphrase error"); 126 goto errOut; 127 } 128 } 129 else { 130 assert(passKey != NULL); 131 ortn = SecPkcs12SetMACPassKey(p12Coder, passKey); 132 if(ortn) { 133 SecImpExpDbg("SecPkcs12SetMACPassphrase error"); 134 goto errOut; 135 } 136 } 137 138 ortn = SecPkcs12ExportKeychainItems(p12Coder, exportItems); 139 if(ortn) { 140 SecImpExpDbg("impExpPkcs12Export: SecPkcs12ExportKeychainItems failure"); 141 goto errOut; 142 } 143 144 /* GO */ 145 ortn = SecPkcs12Encode(p12Coder, &tmpData); 146 if(ortn) { 147 SecImpExpDbg("impExpPkcs12Export: SecPkcs12Encode failure"); 148 goto errOut; 149 } 150 151 /* append encoded data to output */ 152 CFDataAppendBytes(outData, CFDataGetBytePtr(tmpData), CFDataGetLength(tmpData)); 153 154errOut: 155 SecPkcs12CoderRelease(p12Coder); 156 if(passKey != NULL) { 157 CSSM_FreeKey(cspHand, NULL, passKey, CSSM_FALSE); 158 free(passKey); 159 } 160 if(kcRef) { 161 CFRelease(kcRef); 162 } 163 if(exportItems) { 164 CFRelease(exportItems); 165 } 166 if(tmpData) { 167 CFRelease(tmpData); 168 } 169 return ortn; 170} 171 172OSStatus impExpPkcs7Export( 173 CFArrayRef exportReps, // SecExportReps 174 SecItemImportExportFlags flags, // kSecItemPemArmour, etc. 175 const SecKeyImportExportParameters *keyParams, // optional 176 CFMutableDataRef outData) // output appended here 177{ 178 SecCmsSignedDataRef sigd = NULL; 179 SecCertificateRef certRef; 180 OSStatus ortn; 181 CFIndex numCerts = CFArrayGetCount(exportReps); 182 SecExportRep *exportRep; 183 SecCmsContentInfoRef cinfo = NULL; 184 SecArenaPoolRef arena = NULL; 185 SecCmsEncoderRef ecx; 186 CSSM_DATA output = { 0, NULL }; 187 188 if(numCerts == 0) { 189 SecImpExpDbg("impExpPkcs7Export: no certs to export"); 190 return errSecSuccess; 191 } 192 193 /* create the message object */ 194 SecCmsMessageRef cmsg = SecCmsMessageCreate(NULL); 195 if(cmsg == NULL) { 196 SecImpExpDbg("impExpPkcs7Export: SecCmsMessageCreate failure"); 197 return errSecInternalComponent; 198 } 199 200 /* get first cert */ 201 exportRep = (SecExportRep *)CFArrayGetValueAtIndex(exportReps, 0); 202 assert(exportRep != NULL); 203 if(exportRep->externType() != kSecItemTypeCertificate) { 204 SecImpExpDbg("impExpPkcs7Export: non-cert item"); 205 ortn = errSecParam; 206 goto errOut; 207 } 208 certRef = (SecCertificateRef)exportRep->kcItem(); 209 210 /* build chain of objects: message->signedData->data */ 211 sigd = SecCmsSignedDataCreateCertsOnly(cmsg, certRef, false); 212 if(sigd == NULL) { 213 SecImpExpDbg("impExpPkcs7Export: SecCmsSignedDataCreateCertsOnly failure"); 214 ortn = errSecInternalComponent; 215 goto errOut; 216 } 217 218 for (CFIndex dex=1; dex<numCerts; dex++) { 219 exportRep = (SecExportRep *)CFArrayGetValueAtIndex(exportReps, dex); 220 assert(exportRep != NULL); 221 if(exportRep->externType() != kSecItemTypeCertificate) { 222 SecImpExpDbg("impExpPkcs7Export: non-cert item"); 223 ortn = errSecParam; 224 goto errOut; 225 } 226 certRef = (SecCertificateRef)exportRep->kcItem(); 227 ortn = SecCmsSignedDataAddCertChain(sigd, certRef); 228 if(ortn) { 229 SecImpExpDbg("impExpPkcs7Export: SecCmsSignedDataAddCertChain error"); 230 goto errOut; 231 } 232 } 233 234 cinfo = SecCmsMessageGetContentInfo(cmsg); 235 if(cinfo == NULL) { 236 SecImpExpDbg("impExpPkcs7Export: SecCmsMessageGetContentInfo returned NULL"); 237 ortn = errSecInternalComponent; 238 goto errOut; 239 } 240 ortn = SecCmsContentInfoSetContentSignedData(cmsg, cinfo, sigd); 241 if(ortn) { 242 SecImpExpDbg("impExpPkcs7Export: SecCmsContentInfoSetContentSignedData error"); 243 goto errOut; 244 } 245 cinfo = SecCmsSignedDataGetContentInfo(sigd); 246 if(cinfo == NULL) { 247 SecImpExpDbg("impExpPkcs7Export: SecCmsSignedDataGetContentInfo returned NULL"); 248 ortn = errSecInternalComponent; 249 goto errOut; 250 } 251 ortn = SecCmsContentInfoSetContentData(cmsg, cinfo, NULL, 252 false /* FIXME - what's this? */); 253 if(ortn) { 254 SecImpExpDbg("impExpPkcs7Export: SecCmsContentInfoSetContentData error"); 255 goto errOut; 256 } 257 258 /* Now encode it */ 259 ortn = SecArenaPoolCreate(1024, &arena); 260 if(ortn) { 261 SecImpExpDbg("impExpPkcs7Export: SecArenaPoolCreate error"); 262 goto errOut; 263 } 264 ortn = SecCmsEncoderCreate(cmsg, 265 NULL, NULL, /* DER output callback */ 266 &output, arena, /* destination storage */ 267 NULL, NULL, /* password callback */ 268 NULL, NULL, /* decrypt key callback */ 269 NULL, NULL, 270 &ecx ); /* detached digests */ 271 if(ortn) { 272 SecImpExpDbg("impExpPkcs7Export: SecCmsEncoderCreate error"); 273 goto errOut; 274 } 275 ortn = SecCmsEncoderFinish(ecx); 276 if(ortn) { 277 SecImpExpDbg("impExpPkcs7Export: SecCmsEncoderFinish returned NULL"); 278 goto errOut; 279 } 280 281 /* append encoded data to output */ 282 CFDataAppendBytes(outData, output.Data, output.Length); 283 284 285errOut: 286 if(cmsg != NULL) { 287 SecCmsMessageDestroy(cmsg); 288 } 289 if(arena != NULL) { 290 SecArenaPoolFree(arena, false); 291 } 292 return ortn; 293} 294 295#pragma mark --- Aggregate Import routines --- 296 297/* 298 * For all of these, if a cspHand is specified instead of a keychain, 299 * the cspHand MUST be a CSPDL handle, not a raw CSP handle. 300 */ 301OSStatus impExpPkcs12Import( 302 CFDataRef inData, 303 SecItemImportExportFlags flags, 304 const SecKeyImportExportParameters *keyParams, // optional 305 ImpPrivKeyImportState &keyImportState, // IN/OUT 306 307 /* caller must supply one of these */ 308 SecKeychainRef importKeychain, // optional 309 CSSM_CSP_HANDLE cspHand, // required 310 CFMutableArrayRef outArray) // optional, append here 311{ 312 SecPkcs12CoderRef p12Coder = NULL; 313 OSStatus ortn; 314 CFIndex numCerts; 315 CFIndex numKeys; 316 CFIndex dex; 317 CFMutableArrayRef privKeys = NULL; 318 CSSM_KEY *passKey = NULL; 319 CFStringRef phraseStr = NULL; 320 321 /* 322 * Optional private key attrs. 323 * Although the PKCS12 library has its own defaults for these, we'll 324 * set them explicitly to the defaults specified in our API if the 325 * caller doesn't specify any. 326 */ 327 CSSM_KEYUSE keyUsage = CSSM_KEYUSE_ANY; 328 CSSM_KEYATTR_FLAGS keyAttrs = CSSM_KEYATTR_SENSITIVE | CSSM_KEYATTR_EXTRACTABLE | 329 CSSM_KEYATTR_RETURN_REF; 330 331 if( (keyParams == NULL) || 332 ( (keyParams->passphrase == NULL) && 333 !(keyParams->flags & kSecKeySecurePassphrase) ) ) { 334 /* passphrase mandatory */ 335 return errSecPassphraseRequired; 336 } 337 338 /* 339 * Set up a P12 decoder. 340 */ 341 ortn = SecPkcs12CoderCreate(&p12Coder); 342 if(ortn) { 343 SecImpExpDbg("SecPkcs12CoderCreate error"); 344 return ortn; 345 } 346 /* subsequent errors to errOut: */ 347 348 CSSM_CL_HANDLE clHand = cuClStartup(); 349 CSSM_CSP_HANDLE rawCspHand = cuCspStartup(CSSM_TRUE); // for CL 350 if((clHand == 0) || (rawCspHand == 0)) { 351 return CSSMERR_CSSM_ADDIN_LOAD_FAILED; 352 } 353 354 assert(cspHand != CSSM_INVALID_HANDLE); 355 if(importKeychain != NULL) { 356 ortn = SecPkcs12SetKeychain(p12Coder, importKeychain); 357 if(ortn) { 358 SecImpExpDbg("SecPkcs12SetKeychain error"); 359 goto errOut; 360 } 361 } 362 else { 363 if(cspHand == CSSM_INVALID_HANDLE) { 364 ortn = errSecParam; 365 goto errOut; 366 } 367 ortn = SecPkcs12SetCspHandle(p12Coder, cspHand); 368 if(ortn) { 369 SecImpExpDbg("SecPkcs12SetCspHandle error"); 370 goto errOut; 371 } 372 } 373 374 /* explicit passphrase, or get one ourself? */ 375 ortn = impExpPassphraseCommon(keyParams, cspHand, SPF_String, 376 VP_Import, (CFTypeRef *)&phraseStr, &passKey); 377 if(ortn) { 378 goto errOut; 379 } 380 if(phraseStr != NULL) { 381 ortn = SecPkcs12SetMACPassphrase(p12Coder, phraseStr); 382 CFRelease(phraseStr); 383 if(ortn) { 384 SecImpExpDbg("SecPkcs12SetMACPassphrase error"); 385 goto errOut; 386 } 387 } 388 else { 389 assert(passKey != NULL); 390 ortn = SecPkcs12SetMACPassKey(p12Coder, passKey); 391 if(ortn) { 392 SecImpExpDbg("SecPkcs12SetMACPassphrase error"); 393 goto errOut; 394 } 395 } 396 397 if(keyImportState != PIS_NoLimit) { 398 bool foundOneKey = false; 399 400 /* allow either zero or one more private key */ 401 if(keyImportState == PIS_NoMore) { 402 foundOneKey = true; 403 } 404 ortn = SecPkcs12LimitPrivateKeyImport(p12Coder, foundOneKey); 405 if(ortn) { 406 SecImpExpDbg("SecPkcs12LimitPrivateKeyImport error"); 407 goto errOut; 408 } 409 } 410 411 if(keyParams != NULL) { 412 if(keyParams->keyUsage != 0) { 413 keyUsage = keyParams->keyUsage; 414 } 415 if(keyParams->keyAttributes != 0) { 416 keyAttrs = keyParams->keyAttributes; 417 } 418 if(keyParams->flags & kSecKeyNoAccessControl) { 419 ortn = SecPkcs12SetAccess(p12Coder, NULL); 420 if(ortn) { 421 SecImpExpDbg("SecPkcs12SetAccess error"); 422 goto errOut; 423 } 424 } 425 else if(keyParams->accessRef != NULL) { 426 ortn = SecPkcs12SetAccess(p12Coder, keyParams->accessRef); 427 if(ortn) { 428 SecImpExpDbg("SecPkcs12SetAccess error"); 429 goto errOut; 430 } 431 } 432 /* else default ACL */ 433 } 434 ortn = SecPkcs12SetKeyUsage(p12Coder, keyUsage); 435 if(ortn) { 436 SecImpExpDbg("SecPkcs12SetKeyUsage error"); 437 goto errOut; 438 } 439 ortn = SecPkcs12SetKeyAttrs(p12Coder, keyAttrs); 440 if(ortn) { 441 SecImpExpDbg("SecPkcs12SetKeyAttrs error"); 442 goto errOut; 443 } 444 445 /* GO */ 446 ortn = SecPkcs12Decode(p12Coder, inData); 447 if(ortn) { 448 SecImpExpDbg("SecPkcs12Decode error"); 449 goto errOut; 450 } 451 452 /* 453 * About to process SecKeychainItemRefs. 454 * This whole mess is irrelevant if the caller doesn't 455 * want an array of SecKeychainItemRefs. 456 */ 457 if(outArray == NULL) { 458 goto errOut; 459 } 460 461 ortn = SecPkcs12CertificateCount(p12Coder, &numCerts); 462 if(ortn) { 463 SecImpExpDbg("SecPkcs12CertificateCount error"); 464 goto errOut; 465 } 466 ortn = SecPkcs12PrivateKeyCount(p12Coder, &numKeys); 467 if(ortn) { 468 SecImpExpDbg("SecPkcs12PrivateKeyCount error"); 469 goto errOut; 470 } 471 472 /* 473 * Match up certs and keys to create SecIdentityRefs. 474 * First create a temporary array of the private keys 475 * found by the P12 module. 476 * 477 * FIXME we're working with a P12 module which can not 478 * vend SecKeyRefs.....this will hopefully, eventually, 479 * change. 480 */ 481 privKeys = CFArrayCreateMutable(NULL, numKeys, NULL); 482 for(dex=0; dex<numKeys; dex++) { 483 CSSM_KEY_PTR privKey; 484 ortn = SecPkcs12GetCssmPrivateKey(p12Coder, 485 dex, &privKey, NULL, NULL, NULL); 486 CFArrayAppendValue(privKeys, privKey); 487 } 488 489 /* 490 * Now go through all certs, searching for a matching private 491 * key. When we find a match we try to create an identity from the 492 * cert, which might fail for a number of reasons, currently including 493 * the fact that there is no way to create an identity with a key 494 * which does not reside on a keychain. (Such is the case here when 495 * caller has not specified a keychain.) If that works we skip the 496 * cert, delete that key from the privKeys array, and append the 497 * indentity to outArray. If no identity is found we append the 498 * cert to outArray. At the end of this loop, remaining 499 * items in privKeys (of which there will typically be none) are 500 * also appended to outArray. 501 */ 502 for(dex=0; dex<numCerts; dex++) { 503 SecCertificateRef certRef = NULL; // created by P12 504 SecCertificateRef importedCertRef = NULL; // owned by Sec layer 505 CSSM_KEY_PTR pubKey = NULL; // mallocd by CL 506 CSSM_KEY_PTR privKey = NULL; // owned by P12 507 CSSM_DATA certData; // owned by Sec layer 508 CSSM_DATA pubKeyDigest = {0, NULL}; // mallocd by CSP 509 CSSM_DATA privKeyDigest = {0, NULL}; // mallocd by CSP 510 bool foundIdentity = false; 511 512 ortn = SecPkcs12CopyCertificate(p12Coder, dex, &certRef, 513 NULL, NULL, NULL); 514 if(ortn) { 515 /* should never happen */ 516 SecImpExpDbg("SecPkcs12CopyCertificate error"); 517 goto errOut; 518 } 519 /* subsequent errors in this loop to loopEnd: */ 520 521 if(importKeychain == NULL) { 522 /* Skip the Identity match - just return keys and certs */ 523 goto loopEnd; 524 } 525 526 /* the SecPkcs12CopyCertificate function returns a floating 527 * certificate without a keychain. We must update it now that 528 * it has been added to importKeychain. 529 */ 530 { 531 StorageManager::KeychainList keychains; 532 globals().storageManager.optionalSearchList(importKeychain, keychains); 533 SecPointer<Certificate> cert = Certificate::required(certRef); 534 importedCertRef = cert->findInKeychain(keychains)->handle(); 535 } 536 537 /* Get digest of this cert's public key */ 538 ortn = SecCertificateGetData(importedCertRef, &certData); 539 if(ortn) { 540 SecImpExpDbg("SecCertificateGetData error"); 541 goto loopEnd; 542 } 543 ortn = CSSM_CL_CertGetKeyInfo(clHand, &certData, &pubKey); 544 if(ortn) { 545 SecImpExpDbg("SecCertificateGetData error"); 546 goto loopEnd; 547 } 548 ortn = impExpKeyDigest(rawCspHand, pubKey, &pubKeyDigest); 549 if(ortn) { 550 goto loopEnd; 551 } 552 553 /* 554 * Now search for a private key with this same digest 555 */ 556 numKeys = CFArrayGetCount(privKeys); 557 for(CFIndex privDex=0; privDex<numKeys; privDex++) { 558 privKey = (CSSM_KEY_PTR)CFArrayGetValueAtIndex(privKeys, privDex); 559 assert(privKey != NULL); 560 ortn = impExpKeyDigest(cspHand, privKey, &privKeyDigest); 561 if(ortn) { 562 goto loopEnd; 563 } 564 CSSM_BOOL digestMatch = cuCompareCssmData(&pubKeyDigest, &privKeyDigest); 565 impExpFreeCssmMemory(cspHand, privKeyDigest.Data); 566 if(digestMatch) { 567 /* 568 * MATCH: try to cook up Identity. 569 * TBD: I expect some work will be needed here when 570 * Sec layer can handle floating keys. One thing 571 * that would be nice would be if we could create an identity 572 * FROM a given SecCertRef and a SecKeyRef, even if 573 * the SecKeyRef is floating. 574 * 575 * NOTE: you might think that we could do a 576 * SecIdentityCreateWithCertificate() before, or even without, 577 * doing a digest match....but that could "work" without 578 * us having imported any keys at all, if the appropriate 579 * private key were already there. Doing the digest match 580 * guarantees the uniqueness of the key item in the DB. 581 */ 582 SecIdentityRef idRef = NULL; 583 ortn = SecIdentityCreateWithCertificate(importKeychain, 584 importedCertRef, &idRef); 585 if(ortn == errSecSuccess) { 586 /* 587 * Got one! 588 * 589 * -- add Identity to outArray 590 * -- remove privKey from privKeys array 591 * -- skip to next cert 592 */ 593 SecImpExpDbg("P12Import: generating a SecIdentityRef"); 594 assert(outArray != NULL); 595 CFArrayAppendValue(outArray, idRef); 596 CFRelease(idRef); // array holds only ref 597 idRef = NULL; 598 CFArrayRemoveValueAtIndex(privKeys, privDex); 599 foundIdentity = true; 600 goto loopEnd; 601 } /* ID create worked, else try next key */ 602 } /* digest match */ 603 } /* searching thru privKeys */ 604 loopEnd: 605 /* free resources allocated in this loop */ 606 assert(certRef != NULL); 607 if(!foundIdentity ) { 608 /* No private key for this cert: give to caller */ 609 assert(outArray != NULL); 610 CFArrayAppendValue(outArray, certRef); 611 } 612 CFRelease(certRef); // outArray holds only ref 613 certRef = NULL; 614 if (importedCertRef) { 615 CFRelease(importedCertRef); 616 importedCertRef = NULL; 617 } 618 if(pubKey != NULL) { 619 /* technically invalid, the CL used some CSP handle we 620 * don't have access to to get this... */ 621 CSSM_FreeKey(rawCspHand, NULL, pubKey, CSSM_FALSE); 622 impExpFreeCssmMemory(clHand, pubKey); 623 pubKey = NULL; 624 } 625 if(pubKeyDigest.Data != NULL) { 626 impExpFreeCssmMemory(rawCspHand, pubKeyDigest.Data); 627 pubKeyDigest.Data = NULL; 628 } 629 if(ortn) { 630 goto errOut; 631 } 632 } 633 634errOut: 635 /* 636 * One last thing: pass any remaining (non-identity) keys to caller. 637 * For now, the keys are CSSM_KEYs owned by the P12 coder object, we 638 * don't have to release them. When P12 can vend SecKeyRefs, we release the 639 * keys here. 640 */ 641 642 /* 643 The code below has no net effect, except for generating a leak. This was 644 found while investigating 645 <rdar://problem/8799913> SecItemImport() leaking 646 Code like this will need to be added when we return SecIdentityRefs in 647 the "in memory" case (destKeychain = NULL). Currently, when importing to 648 a physical keychain, the returned item array contains SecIdentityRefs, 649 whereas the "in memory" case returns SecCertificateRefs. See 650 <rdar://problem/8862809> ER: SecItemImport should return SecIdentityRefs in the "in memory" case 651 652 */ 653#if 0 654 if(privKeys) { 655 if(ortn == errSecSuccess) { // TBD OR keys are SecKeyRefs 656 numKeys = CFArrayGetCount(privKeys); 657 for(dex=0; dex<numKeys; dex++) { 658 SecKeyRef keyRef; 659 CSSM_KEY_PTR privKey = 660 (CSSM_KEY_PTR)CFArrayGetValueAtIndex(privKeys, dex); 661 assert(privKey != NULL); 662 if(ortn == errSecSuccess) { 663 /* only do this on complete success so far */ 664 ortn = SecKeyCreateWithCSSMKey(privKey, &keyRef); 665 if(ortn) { 666 SecImpExpDbg("SecKeyCreateWithCSSMKey error"); 667 } 668 /* keep going for CFRelease */ 669 if (keyRef) 670 CFRelease(keyRef); 671 } 672 /* TBD CFRelease the SecKeyRef */ 673 } /* for each privKey */ 674 } /* success so far */ 675 } 676#endif 677 678 SecPkcs12CoderRelease(p12Coder); 679 if(passKey != NULL) { 680 CSSM_FreeKey(cspHand, NULL, passKey, CSSM_FALSE); 681 free(passKey); 682 } 683 if(privKeys != NULL) { 684 CFRelease(privKeys); 685 } 686 if(clHand != 0) { 687 cuClDetachUnload(clHand); 688 } 689 if(rawCspHand != 0) { 690 cuCspDetachUnload(rawCspHand, CSSM_TRUE); 691 } 692 return ortn; 693} 694 695OSStatus impExpPkcs7Import( 696 CFDataRef inData, 697 SecItemImportExportFlags flags, 698 const SecKeyImportExportParameters *keyParams, // optional 699 SecKeychainRef importKeychain, // optional 700 CFMutableArrayRef outArray) // optional, append here 701{ 702 SecCmsDecoderRef decoderContext; 703 SecCmsMessageRef cmsMessage = NULL; 704 SecCmsContentInfoRef contentInfo; 705 SecCmsSignedDataRef signedData; 706 int contentLevelCount; 707 int i; 708 SECOidTag contentTypeTag; 709 OSStatus result; 710 OSStatus ourRtn = errSecSuccess; 711 712 /* decode the message */ 713 result = SecCmsDecoderCreate (NULL, NULL, NULL, NULL, NULL, NULL, NULL, &decoderContext); 714 if (result != 0) { 715 ourRtn = result; 716 goto errOut; 717 } 718 result = SecCmsDecoderUpdate(decoderContext, CFDataGetBytePtr(inData), 719 CFDataGetLength(inData)); 720 if (result != 0) { 721 /* any useful status here? */ 722 SecImpExpDbg("SecCmsDecoderUpdate error"); 723 ourRtn = errSecUnknownFormat; 724 SecCmsDecoderDestroy(decoderContext); 725 goto errOut; 726 } 727 728 ourRtn = SecCmsDecoderFinish(decoderContext, &cmsMessage); 729 if (ourRtn) { 730 SecImpExpDbg("SecCmsDecoderFinish error"); 731 ourRtn = errSecUnknownFormat; 732 goto errOut; 733 } 734 735 // process the results 736 contentLevelCount = SecCmsMessageContentLevelCount (cmsMessage); 737 738 for (i = 0; i < contentLevelCount; ++i) 739 { 740 // get content information 741 contentInfo = SecCmsMessageContentLevel (cmsMessage, i); 742 contentTypeTag = SecCmsContentInfoGetContentTypeTag (contentInfo); 743 744 switch (contentTypeTag) 745 { 746 case SEC_OID_PKCS7_SIGNED_DATA: 747 { 748 /* I guess this the only interesting field */ 749 signedData = 750 (SecCmsSignedDataRef) SecCmsContentInfoGetContent (contentInfo); 751 if (signedData == NULL) { 752 SecImpExpDbg("SecCmsContentInfoGetContent returned NULL"); 753 ourRtn = errSecUnknownFormat; 754 goto errOut; 755 } 756 757 // import the certificates 758 CSSM_DATA **outCerts = SecCmsSignedDataGetCertificateList(signedData); 759 if(outCerts == NULL) { 760 SecImpExpDbg("SecCmsSignedDataGetCertificateList returned NULL"); 761 ourRtn = errSecUnknownFormat; 762 goto errOut; 763 } 764 765 /* Returned value is NULL-terminated array */ 766 unsigned count = 0; 767 CSSM_DATA **array = outCerts; 768 if (array) { 769 while (*array++) { 770 count++; 771 } 772 } 773 if(count == 0) { 774 SecImpExpDbg("No certs found in apparently good PKCS7 blob"); 775 goto errOut; 776 } 777 778 for(unsigned dex=0; dex<count; dex++) { 779 ourRtn = impExpImportCertCommon(outCerts[dex], importKeychain, 780 outArray); 781 if(ourRtn) { 782 goto errOut; 783 } 784 } 785 break; 786 } 787 default: 788 break; 789 } 790 } 791errOut: 792 if(cmsMessage) { 793 SecCmsMessageDestroy(cmsMessage); 794 } 795 return ourRtn; 796 797} 798 799/* 800 * Import a netscape-cert-sequence. Suitable for low-cost guessing when neither 801 * importKeychain nor outArray is specified. 802 */ 803OSStatus impExpNetscapeCertImport( 804 CFDataRef inData, 805 SecItemImportExportFlags flags, 806 const SecKeyImportExportParameters *keyParams, // optional 807 SecKeychainRef importKeychain, // optional 808 CFMutableArrayRef outArray) // optional, append here 809{ 810 SecNssCoder coder; 811 NetscapeCertSequence certSeq; 812 813 /* DER-decode */ 814 memset(&certSeq, 0, sizeof(certSeq)); 815 PRErrorCode perr = coder.decode(CFDataGetBytePtr(inData), 816 CFDataGetLength(inData), 817 NetscapeCertSequenceTemplate, 818 &certSeq); 819 if(perr) { 820 SecImpExpDbg("impExpNetscapeCertImport: DER decode failure"); 821 return errSecUnknownFormat; 822 } 823 824 /* verify (contentType == netscape-cert-sequence) */ 825 if(!cuCompareOid(&CSSMOID_NetscapeCertSequence, &certSeq.contentType)) { 826 SecImpExpDbg("impExpNetscapeCertImport: OID mismatch"); 827 return errSecUnknownFormat; 828 } 829 830 /* Extract certs in CSSM_DATA form, return to caller */ 831 unsigned numCerts = nssArraySize((const void **)certSeq.certs); 832 for(unsigned i=0; i<numCerts; i++) { 833 CSSM_DATA *cert = certSeq.certs[i]; 834 OSStatus ortn = impExpImportCertCommon(cert, importKeychain, outArray); 835 if(ortn) { 836 return ortn; 837 } 838 } 839 return errSecSuccess; 840} 841 842#pragma mark --- Utilities --- 843 844OSStatus impExpImportCertCommon( 845 const CSSM_DATA *cdata, 846 SecKeychainRef importKeychain, // optional 847 CFMutableArrayRef outArray) // optional, append here 848{ 849 OSStatus ortn = errSecSuccess; 850 SecCertificateRef certRef; 851 852 if (!cdata) 853 return errSecUnsupportedFormat; 854 855 CFDataRef data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)cdata->Data, (CFIndex)cdata->Length, kCFAllocatorNull); 856 /* Pass kCFAllocatorNull as bytesDeallocator to assure the bytes aren't freed */ 857 if (!data) 858 return errSecUnsupportedFormat; 859 860 certRef = SecCertificateCreateWithData(kCFAllocatorDefault, data); 861 CFRelease(data); /* certRef has its own copy of the data now */ 862 if(!certRef) { 863 SecImpExpDbg("impExpHandleCert error\n"); 864 return errSecUnsupportedFormat; 865 } 866 867 if(importKeychain != NULL) { 868 ortn = SecCertificateAddToKeychain(certRef, importKeychain); 869 if(ortn) { 870 SecImpExpDbg("SecCertificateAddToKeychain error\n"); 871 CFRelease(certRef); 872 return ortn; 873 } 874 } 875 if(outArray != NULL) { 876 CFArrayAppendValue(outArray, certRef); 877 } 878 CFRelease(certRef); 879 return ortn; 880} 881 882