/* * Copyright (c) 2003-2004 Apple Computer, Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ /* * pkcs12Keychain.h - P12Coder keychain-related functions. */ #include "pkcs12Coder.h" #include "pkcs12Templates.h" #include "pkcs12Utils.h" #include "pkcs12Debug.h" #include "pkcs12Crypto.h" #include #include // cuAddCrlToDb() #include #include #include /* private API! */ /* * Store the results of a successful decode in app-specified * keychain per mImportFlags. Also assign public key hash attributes to any * private keys found. */ void P12Coder::storeDecodeResults() { assert(mKeychain != NULL); assert(mDlDbHand.DLHandle != 0); if(mImportFlags & kSecImportKeys) { setPrivateKeyHashes(); } if(mImportFlags & kSecImportCertificates) { for(unsigned dex=0; dexgetSecCert(); OSStatus ortn = SecCertificateAddToKeychain(secCert, mKeychain); CFRelease(secCert); switch(ortn) { case noErr: // normal p12DecodeLog("cert added to keychain"); break; case errSecDuplicateItem: // dup cert, OK< skip p12DecodeLog("skipping dup cert"); break; default: p12ErrorLog("SecCertificateAddToKeychain failure\n"); MacOSError::throwMe(ortn); } } } if(mImportFlags & kSecImportCRLs) { for(unsigned dex=0; dexcrlData(), NULL); // no URI known switch(crtn) { case CSSM_OK: // normal p12DecodeLog("CRL added to keychain"); break; case CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA: // dup, ignore p12DecodeLog("skipping dup CRL"); break; default: p12LogCssmError("Error adding CRL to keychain", crtn); CssmError::throwMe(crtn); } } } } /* * Assign appropriate public key hash attribute to each * private key. */ void P12Coder::setPrivateKeyHashes() { for(unsigned dex=0; dexfriendlyName(); CSSM_RETURN crtn = p12SetPubKeyHash(mCspHand, mDlDbHand, rawCspHand(), clHand(), certBag->certData(), keyBag->label(), p12StringToUtf8(friendlyName, mCoder), mCoder, newLabel); if(friendlyName) { CFRelease(friendlyName); } if(crtn) { p12ErrorLog("p12SetPubKeyHash failure\n"); if(crtn == CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA) { /* report in a keychain-friendly way */ MacOSError::throwMe(errSecDuplicateItem); } else { CssmError::throwMe(crtn); } } /* update key's label in case we have to delete on error */ keyBag->setLabel(newLabel); p12DecodeLog("set pub key hash for private key"); } } /* * Given a P12KeyBag, find a matching P12CertBag. Keys and certs * "match" if their localKeyIds match. Returns NULL if not found. */ P12CertBag *P12Coder::findCertForKey( P12KeyBag *keyBag) { assert(keyBag != NULL); CSSM_DATA &keyKeyId = keyBag->localKeyIdCssm(); for(unsigned dex=0; dexlocalKeyIdCssm(); if(nssCompareCssmData(&keyKeyId, &certKeyId)) { p12DecodeLog("findCertForKey SUCCESS"); return certBag; } } p12DecodeLog("findCertForKey FAILURE"); return NULL; } /* * Export items specified as SecKeychainItemRefs. */ void P12Coder::exportKeychainItems( CFArrayRef items) { assert(items != NULL); CFIndex numItems = CFArrayGetCount(items); for(CFIndex dex=0; dexAttributeName)) { *attrInt = info->AttributeId; return noErr; } } return paramErr; } void P12Coder::addSecKey( SecKeyRef keyRef) { /* get the cert's attrs (not data) */ /* * Convert the attr name strings we happen to know about to * unknowable name-as-int values. */ UInt32 printNameTag; OSStatus ortn = attrNameToInt(P12_KEY_ATTR_PRINT_NAME, &printNameTag); if(ortn) { p12ErrorLog("addSecKey: problem looking up key attr name\n"); MacOSError::throwMe(ortn); } UInt32 labelHashTag; ortn = attrNameToInt(P12_KEY_ATTR_LABEL_AND_HASH, &labelHashTag); if(ortn) { p12ErrorLog("addSecKey: problem looking up key attr name\n"); MacOSError::throwMe(ortn); } UInt32 tags[2]; tags[0] = printNameTag; tags[1] = labelHashTag; /* I don't know what the format field is for */ SecKeychainAttributeInfo attrInfo; attrInfo.count = 2; attrInfo.tag = tags; attrInfo.format = NULL; // ??? /* FIXME header says this is an IN/OUT param, but it's not */ SecKeychainAttributeList *attrList = NULL; ortn = SecKeychainItemCopyAttributesAndData( (SecKeychainItemRef)keyRef, &attrInfo, NULL, // itemClass &attrList, NULL, // don't need the data NULL); if(ortn) { p12ErrorLog("addSecKey: SecKeychainItemCopyAttributesAndData " "error\n"); MacOSError::throwMe(ortn); } /* Snag the attrs, convert to something useful */ CFStringRef friendName = NULL; CFDataRef localKeyId = NULL; for(unsigned i=0; icount; i++) { SecKeychainAttribute *attr = &attrList->attr[i]; if(attr->tag == printNameTag) { friendName = CFStringCreateWithBytes(NULL, (UInt8 *)attr->data, attr->length, kCFStringEncodingUTF8, false); } else if(attr->tag == labelHashTag) { localKeyId = CFDataCreate(NULL, (UInt8 *)attr->data, attr->length); } else { p12ErrorLog("addSecKey: unexpected attr tag\n"); MacOSError::throwMe(paramErr); } } /* * Infer the CSP associated with this key. * FIXME: this should be an attribute of the SecKeyRef itself, * not inferred from the keychain it happens to be living on * (SecKeyRefs should not have to be attached to Keychains at * this point). */ SecKeychainRef kcRef; ortn = SecKeychainItemCopyKeychain((SecKeychainItemRef)keyRef, &kcRef); if(ortn) { p12ErrorLog("addSecKey: SecKeychainItemCopyKeychain returned %d\n", (int)ortn); MacOSError::throwMe(ortn); } CSSM_CSP_HANDLE cspHand; ortn = SecKeychainGetCSPHandle(kcRef, &cspHand); if(ortn) { p12ErrorLog("addSecKey: SecKeychainGetCSPHandle returned %d\n", (int)ortn); MacOSError::throwMe(ortn); } CFRelease(kcRef); /* and the CSSM_KEY itself */ const CSSM_KEY *cssmKey; ortn = SecKeyGetCSSMKey(keyRef, &cssmKey); if(ortn) { p12ErrorLog("addSecKey: SecKeyGetCSSMKey returned %d\n", (int)ortn); MacOSError::throwMe(ortn); } /* Cook up a key bag and save it */ P12KeyBag *keyBag = new P12KeyBag(cssmKey, cspHand, friendName, localKeyId, NULL, // other attrs mCoder, keyRef); addKey(keyBag); SecKeychainItemFreeAttributesAndData(attrList, NULL); if(friendName) { CFRelease(friendName); } if(localKeyId) { CFRelease(localKeyId); } } void P12Coder::addSecCert( SecCertificateRef certRef) { /* get the cert's attrs and data */ /* I don't know what the format field is for */ SecKeychainAttributeInfo attrInfo; attrInfo.count = 2; UInt32 tags[2] = {kSecLabelItemAttr, kSecPublicKeyHashItemAttr}; attrInfo.tag = tags; attrInfo.format = NULL; // ??? /* FIXME header says this is an IN/OUT param, but it's not */ SecKeychainAttributeList *attrList = NULL; UInt32 certLen; void *certData; OSStatus ortn = SecKeychainItemCopyAttributesAndData( (SecKeychainItemRef)certRef, &attrInfo, NULL, // itemClass &attrList, &certLen, &certData); if(ortn) { p12ErrorLog("addSecCert: SecKeychainItemCopyAttributesAndData " "error\n"); MacOSError::throwMe(ortn); } /* Snag the attrs, convert to something useful */ CFStringRef friendName = NULL; CFDataRef localKeyId = NULL; for(unsigned i=0; icount; i++) { SecKeychainAttribute *attr = &attrList->attr[i]; switch(attr->tag) { case kSecPublicKeyHashItemAttr: localKeyId = CFDataCreate(NULL, (UInt8 *)attr->data, attr->length); break; case kSecLabelItemAttr: /* FIXME: always in UTF8? */ friendName = CFStringCreateWithBytes(NULL, (UInt8 *)attr->data, attr->length, kCFStringEncodingUTF8, false); break; default: p12ErrorLog("addSecCert: unexpected attr tag\n"); MacOSError::throwMe(paramErr); } } /* Cook up a cert bag and save it */ CSSM_DATA cData = {certLen, (uint8 *)certData}; P12CertBag *certBag = new P12CertBag(CT_X509, cData, friendName, localKeyId, NULL, mCoder); addCert(certBag); SecKeychainItemFreeAttributesAndData(attrList, certData); if(friendName) { CFRelease(friendName); } if(localKeyId) { CFRelease(localKeyId); } } /* * Delete anything stored in a keychain during decode, called on * decode error. * Currently the only thing we have to deal with is private keys, * since certs and CRLs don't get stored until the end of a successful * decode. */ void P12Coder::deleteDecodedItems() { if(!(mImportFlags & kSecImportKeys)) { /* no keys stored, done */ return; } if(mDlDbHand.DLHandle == 0) { /* no keychain, done */ return; } unsigned nKeys = numKeys(); for(unsigned dex=0; dexlabel()); } }