// Takes the "context" policies to extract the revocation and apply it to timeStamp. CFArrayRef SecPolicyCreateAppleTimeStampingAndRevocationPolicies(CFTypeRef policyOrArray) { /* can't use SECAPI macros, since this function does not return OSStatus */ CFArrayRef resultPolicyArray=NULL; try { // Set default policy CFRef<CFArrayRef> policyArray = cfArrayize(policyOrArray); CFRef<SecPolicyRef> defaultPolicy = SecPolicyCreateWithOID(kSecPolicyAppleTimeStamping); CFRef<CFMutableArrayRef> appleTimeStampingPolicies = makeCFMutableArray(1,defaultPolicy.get()); // Parse the policy and add revocation related ones CFIndex numPolicies = CFArrayGetCount(policyArray); for(CFIndex dex=0; dex<numPolicies; dex++) { SecPolicyRef secPol = (SecPolicyRef)CFArrayGetValueAtIndex(policyArray, dex); SecPointer<Policy> pol = Policy::required(SecPolicyRef(secPol)); const CssmOid &oid = pol->oid(); if ((oid == CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION)) || (oid == CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_CRL)) || (oid == CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_OCSP))) { CFArrayAppendValue(appleTimeStampingPolicies, secPol); } } // Transfer of ownership resultPolicyArray=appleTimeStampingPolicies.yield(); } catch (...) { CFReleaseNull(resultPolicyArray); }; return resultPolicyArray; }
// // Identify a guest by returning its StaticCode and running CodeDirectory hash. // This uses cshosting RPCs to ask the host (or its proxy). // SecStaticCode *GenericCode::identifyGuest(SecCode *guest, CFDataRef *cdhashOut) { if (GenericCode *iguest = dynamic_cast<GenericCode *>(guest)) { FilePathOut path; CFRef<CFDataRef> cdhash; CFDictionary attributes(errSecCSHostProtocolInvalidAttribute); identifyGuest(iguest->guestRef(), path, cdhash.aref(), attributes.aref()); DiskRep::Context ctx; if (CFNumberRef architecture = attributes.get<CFNumberRef>(kSecGuestAttributeArchitecture)) { cpu_type_t cpu = cfNumber<cpu_type_t>(architecture); if (CFNumberRef subarchitecture = attributes.get<CFNumberRef>(kSecGuestAttributeSubarchitecture)) ctx.arch = Architecture(cpu, cfNumber<cpu_subtype_t>(subarchitecture)); else ctx.arch = Architecture(cpu); } SecPointer<GenericStaticCode> code = new GenericStaticCode(DiskRep::bestGuess(path, &ctx)); CODESIGN_GUEST_IDENTIFY_GENERIC(iguest, iguest->guestRef(), code); if (cdhash) { CODESIGN_GUEST_CDHASH_GENERIC(iguest, (void *)CFDataGetBytePtr(cdhash), (unsigned)CFDataGetLength(cdhash)); *cdhashOut = cdhash.yield(); } return code.yield(); } else MacOSError::throwMe(errSecCSNotAHost); }
// // Given a bag of attribute values, automagically come up with a SecCode // without any other information. // This is meant to be the "just do what makes sense" generic call, for callers // who don't want to engage in the fascinating dance of manual guest enumeration. // // Note that we expect the logic embedded here to change over time (in backward // compatible fashion, one hopes), and that it's all right to use heuristics here // as long as it's done sensibly. // // Be warned that the present logic is quite a bit ad-hoc, and will likely not // handle arbitrary combinations of proxy hosting, dynamic hosting, and dedicated // hosting all that well. // SecCode *SecCode::autoLocateGuest(CFDictionaryRef attributes, SecCSFlags flags) { // special case: with no attributes at all, return the root of trust if (CFDictionaryGetCount(attributes) == 0) return KernelCode::active()->retain(); // main logic: we need a pid, and we'll take a canonical guest id as an option int pid = 0; if (!cfscan(attributes, "{%O=%d}", kSecGuestAttributePid, &pid)) CSError::throwMe(errSecCSUnsupportedGuestAttributes, kSecCFErrorGuestAttributes, attributes); if (SecCode *process = KernelCode::active()->locateGuest(attributes)) { SecPointer<SecCode> code; code.take(process); // locateGuest gave us a retained object if (code->staticCode()->flag(kSecCodeSignatureHost)) { // might be a code host. Let's find out CFRef<CFMutableDictionaryRef> rest = makeCFMutableDictionary(attributes); CFDictionaryRemoveValue(rest, kSecGuestAttributePid); if (SecCode *guest = code->locateGuest(rest)) return guest; } if (!CFDictionaryGetValue(attributes, kSecGuestAttributeCanonical)) { // only "soft" attributes, and no hosting is happening. Return the (non-)host itself return code.yield(); } } MacOSError::throwMe(errSecCSNoSuchCode); }
/*! */ OSStatus SecAccessCreateFromOwnerAndACL(const CSSM_ACL_OWNER_PROTOTYPE *owner, uint32 aclCount, const CSSM_ACL_ENTRY_INFO *acls, SecAccessRef *accessRef) { BEGIN_SECAPI Required(accessRef); // preflight SecPointer<Access> access = new Access(Required(owner), aclCount, &Required(acls)); *accessRef = access->handle(); END_SECAPI }
// // Get the host for an Code // OSStatus SecCodeCopyHost(SecCodeRef guestRef, SecCSFlags flags, SecCodeRef *hostRef) { BEGIN_CSAPI checkFlags(flags); SecPointer<SecCode> host = SecCode::required(guestRef)->host(); CodeSigning::Required(hostRef) = host ? host->handle() : NULL; END_CSAPI }
/*! */ OSStatus SecACLCopySimpleContents(SecACLRef aclRef, CFArrayRef *applicationList, CFStringRef *promptDescription, CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR *promptSelector) { BEGIN_SECAPI SecPointer<ACL> acl = ACL::required(aclRef); switch (acl->form()) { case ACL::allowAllForm: Required(applicationList) = NULL; Required(promptDescription) = acl->promptDescription().empty() ? NULL : makeCFString(acl->promptDescription()); Required(promptSelector) = acl->promptSelector(); break; case ACL::appListForm: Required(applicationList) = makeCFArrayFrom(convert, acl->applications()); Required(promptDescription) = makeCFString(acl->promptDescription()); Required(promptSelector) = acl->promptSelector(); break; case ACL::integrityForm: Required(applicationList) = NULL; Required(promptDescription) = makeCFString(acl->integrity().toHex()); // We don't have a prompt selector. Nullify. Required(promptSelector).version = CSSM_ACL_KEYCHAIN_PROMPT_CURRENT_VERSION; Required(promptSelector).flags = 0; break; default: return errSecACLNotSimple; // custom or unknown } END_SECAPI }
OSStatus SecACLSetSimpleContents(SecACLRef aclRef, CFArrayRef applicationList, CFStringRef description, const CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR *promptSelector) { BEGIN_SECAPI SecPointer<ACL> acl = ACL::required(aclRef); if(acl->form() == ACL::integrityForm) { // If this is an integrity ACL, route the (unhexified) promptDescription into the right place string hex = cfString(description); if(hex.length() %2 == 0) { // might be a valid hex string, try to set CssmAutoData data(Allocator::standard()); data.malloc(hex.length() / 2); data.get().fromHex(hex.c_str()); acl->setIntegrity(data); } } else { // Otherwise, put it in the promptDescription where it belongs acl->promptDescription() = description ? cfString(description) : ""; } acl->promptSelector() = promptSelector ? *promptSelector : ACL::defaultSelector; if(acl->form() != ACL::integrityForm) { if (applicationList) { // application-list + prompt acl->form(ACL::appListForm); setApplications(acl, applicationList); } else { // allow-any acl->form(ACL::allowAllForm); } } acl->modify(); END_SECAPI }
OSStatus SecKeychainItemCopyAccess(SecKeychainItemRef itemRef, SecAccessRef* accessRef) { BEGIN_SECKCITEMAPI Required(accessRef); // preflight SecPointer<Access> access = new Access(*aclBearer(reinterpret_cast<CFTypeRef>(__itemImplRef))); *accessRef = access->handle(); END_SECKCITEMAPI }
void MachOEditor::parentAction() { if (mHelperOverridden) { CODESIGN_ALLOCATE_VALIDATE((char*)mHelperPath, this->pid()); // check code identity of an overridden allocation helper SecPointer<SecStaticCode> code = new SecStaticCode(DiskRep::bestGuess(mHelperPath)); code->validateDirectory(); code->validateExecutable(); code->validateResources(); code->validateRequirement((const Requirement *)appleReq, errSecCSReqFailed); } }
static OSStatus SecAccessCreateFromObject(CFTypeRef sourceRef, SecAccessRef *accessRef) { BEGIN_SECAPI Required(accessRef); // preflight SecPointer<Access> access = new Access(*aclBearer(sourceRef)); *accessRef = access->handle(); END_SECAPI }
OSStatus SecACLSetAuthorizations(SecACLRef aclRef, CSSM_ACL_AUTHORIZATION_TAG *tags, uint32 tagCount) { BEGIN_SECAPI SecPointer<ACL> acl = ACL::required(aclRef); if (acl->isOwner()) // can't change rights of the owner ACL MacOSError::throwMe(errSecInvalidOwnerEdit); AclAuthorizationSet &auths = acl->authorizations(); auths.clear(); copy(tags, tags + tagCount, insert_iterator<AclAuthorizationSet>(auths, auths.begin())); acl->modify(); END_SECAPI }
SecPolicyRef SecPolicyCreateWithSecAsn1Oid(SecAsn1Oid *oidPtr) { SecPolicyRef policy = NULL; try { SecPointer<Policy> policyObj; PolicyCursor::policy(oidPtr, policyObj); policy = policyObj->handle(); } catch (...) {} return policy; }
// // Add a code object to the whitelist // void OpaqueWhitelist::add(SecStaticCodeRef codeRef) { // make our own copy of the code object SecPointer<SecStaticCode> code = new SecStaticCode(SecStaticCode::requiredStatic(codeRef)->diskRep()); CFCopyRef<CFDataRef> current = code->cdHash(); attachOpaque(code->handle(false), NULL); // compute and attach an opaque signature CFDataRef opaque = code->cdHash(); SQLite::Statement insert(*this, "INSERT OR REPLACE INTO whitelist (current,opaque) VALUES (:current, :opaque)"); insert.bind(":current") = current.get(); insert.bind(":opaque") = opaque; insert.execute(); }
/* * Given an app-specified array of Policies, determine if at least one of them * matches the given policy OID. */ bool Trust::policySpecified(CFArrayRef policies, const CSSM_OID &inOid) { if(policies == NULL) { return false; } CFIndex numPolicies = CFArrayGetCount(policies); for(CFIndex dex=0; dex<numPolicies; dex++) { SecPolicyRef secPol = (SecPolicyRef)CFArrayGetValueAtIndex(policies, dex); SecPointer<Policy> pol = Policy::required(SecPolicyRef(secPol)); const CssmOid &oid = pol->oid(); if(oid == CssmOid::overlay(inOid)) { return true; } } return false; }
OSStatus SecIdentitySearchCopyNext( SecIdentitySearchRef searchRef, SecIdentityRef *identityRef) { BEGIN_SECAPI RequiredParam(identityRef); SecPointer<Identity> identityPtr; if (!IdentityCursor::required(searchRef)->next(identityPtr)) return errSecItemNotFound; *identityRef = identityPtr->handle(); END_SECAPI }
OSStatus SecCodeCheckValidityWithErrors(SecCodeRef codeRef, SecCSFlags flags, SecRequirementRef requirementRef, CFErrorRef *errors) { BEGIN_CSAPI checkFlags(flags, kSecCSConsiderExpiration | kSecCSStrictValidate | kSecCSRestrictSidebandData | kSecCSEnforceRevocationChecks); SecPointer<SecCode> code = SecCode::required(codeRef); code->checkValidity(flags); if (const SecRequirement *req = SecRequirement::optional(requirementRef)) code->staticCode()->validateRequirement(req->requirement(), errSecCSReqFailed); END_CSAPI_ERRORS }
// // Get the StaticCode for an Code // OSStatus SecCodeCopyStaticCode(SecCodeRef codeRef, SecCSFlags flags, SecStaticCodeRef *staticCodeRef) { BEGIN_CSAPI checkFlags(flags, kSecCSUseAllArchitectures); SecPointer<SecStaticCode> staticCode = SecCode::required(codeRef)->staticCode(); if (flags & kSecCSUseAllArchitectures) if (Universal* macho = staticCode->diskRep()->mainExecutableImage()) // Mach-O main executable if (macho->narrowed()) { // create a new StaticCode comprising the whole fat file RefPointer<DiskRep> rep = DiskRep::bestGuess(staticCode->diskRep()->mainExecutablePath()); staticCode = new SecStaticCode(rep); } CodeSigning::Required(staticCodeRef) = staticCode ? staticCode->handle() : NULL; END_CSAPI }
/*! * Create a new SecAccessRef that is set to the default configuration * of a (newly created) security object. */ OSStatus SecAccessCreate(CFStringRef descriptor, CFArrayRef trustedList, SecAccessRef *accessRef) { BEGIN_SECAPI Required(descriptor); SecPointer<Access> access; if (trustedList) { CFIndex length = CFArrayGetCount(trustedList); ACL::ApplicationList trusted; for (CFIndex n = 0; n < length; n++) trusted.push_back(TrustedApplication::required( SecTrustedApplicationRef(CFArrayGetValueAtIndex(trustedList, n)))); access = new Access(cfString(descriptor), trusted); } else { access = new Access(cfString(descriptor)); } Required(accessRef) = access->handle(); END_SECAPI }
/* * Obtain non-normalized issuer and serial number for specified cert, both * returned as CFDataRefs owned by caller. */ void TrustSettings::copyIssuerAndSerial( SecCertificateRef certRef, CFDataRef *issuer, /* optional, RETURNED */ CFDataRef *serial) /* RETURNED */ { SecPointer<Certificate> cert = Certificate::required(certRef); CSSM_DATA_PTR fieldVal; if(issuer != NULL) { fieldVal = cert->copyFirstFieldValue(CSSMOID_X509V1IssuerNameStd); *issuer = CFDataCreate(NULL, fieldVal->Data, fieldVal->Length); cert->releaseFieldValue(CSSMOID_X509V1IssuerNameStd, fieldVal); } fieldVal = cert->copyFirstFieldValue(CSSMOID_X509V1SerialNumber); *serial = CFDataCreate(NULL, fieldVal->Data, fieldVal->Length); cert->releaseFieldValue(CSSMOID_X509V1SerialNumber, fieldVal); }
/* * Given an app-specified array of Policies, determine if at least one of them * is an explicit revocation policy. */ bool Trust::revocationPolicySpecified(CFArrayRef policies) { if(policies == NULL) { return false; } CFIndex numPolicies = CFArrayGetCount(policies); for(CFIndex dex=0; dex<numPolicies; dex++) { SecPolicyRef secPol = (SecPolicyRef)CFArrayGetValueAtIndex(policies, dex); SecPointer<Policy> pol = Policy::required(SecPolicyRef(secPol)); const CssmOid &oid = pol->oid(); if(oid == CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_CRL)) { return true; } if(oid == CssmOid::overlay(CSSMOID_APPLE_TP_REVOCATION_OCSP)) { return true; } } return false; }
OSStatus SecPolicyCopyAll(CSSM_CERT_TYPE certificateType, CFArrayRef* policies) { BEGIN_SECAPI Required(policies); CFMutableArrayRef currPolicies = NULL; currPolicies = CFArrayCreateMutable(NULL, 0, NULL); if ( currPolicies ) { SecPointer<PolicyCursor> cursor(new PolicyCursor(NULL, NULL)); SecPointer<Policy> policy; while ( cursor->next(policy) ) /* copies the next policy */ { CFArrayAppendValue(currPolicies, policy->handle()); /* 'SecPolicyRef' appended */ CFRelease(policy->handle()); /* refcount bumped up when appended to array */ } *policies = CFArrayCreateCopy(NULL, currPolicies); CFRelease(currPolicies); CFRelease(cursor->handle()); } END_SECAPI }
OSStatus SecCodeCopySigningInformation(SecStaticCodeRef codeRef, SecCSFlags flags, CFDictionaryRef *infoRef) { BEGIN_CSAPI checkFlags(flags, kSecCSInternalInformation | kSecCSSigningInformation | kSecCSRequirementInformation | kSecCSDynamicInformation | kSecCSContentInformation); SecPointer<SecStaticCode> code = SecStaticCode::requiredStatic(codeRef); CFRef<CFDictionaryRef> info = code->signingInformation(flags); if (flags & kSecCSDynamicInformation) if (SecPointer<SecCode> dcode = SecStaticCode::optionalDynamic(codeRef)) info.take(cfmake<CFDictionaryRef>("{+%O,%O=%u}", info.get(), kSecCodeInfoStatus, dcode->status())); CodeSigning::Required(infoRef) = info.yield(); END_CSAPI }
// // Identify a guest by attribute set, and return a new GenericCode representing it. // This uses cshosting RPCs to ask the host (or its proxy). // SecCode *GenericCode::locateGuest(CFDictionaryRef attributes) { if (Port host = hostingPort()) { CFRef<CFDataRef> attrData; void *attrPtr = NULL; size_t attrLength = 0; if (attributes) { attrData.take(CFPropertyListCreateXMLData(NULL, attributes)); attrPtr = (void *)CFDataGetBytePtr(attrData); attrLength = CFDataGetLength(attrData); } GuestChain guestPath; mach_msg_type_number_t guestPathLength; mach_port_t subport; CALL(host, findGuest, guestRef(), attrPtr, (mach_msg_type_number_t)attrLength, &guestPath, &guestPathLength, &subport); CODESIGN_GUEST_LOCATE_GENERIC(this, guestPath, guestPathLength, subport); SecPointer<SecCode> code = this; for (unsigned n = 0; n < guestPathLength; n++) code = new GenericCode(code, guestPath[n]); return code.yield(); } else return NULL; // not found, no error }
OSStatus SecKeyGenerateWithAttributes( SecKeychainAttributeList* attrList, SecKeychainRef keychainRef, CSSM_ALGORITHMS algorithm, uint32 keySizeInBits, CSSM_CC_HANDLE contextHandle, CSSM_KEYUSE keyUsage, uint32 keyAttr, SecAccessRef initialAccess, SecKeyRef* keyRef) { BEGIN_SECAPI Keychain keychain; SecPointer<Access> theAccess; if (keychainRef) keychain = KeychainImpl::required(keychainRef); if (initialAccess) theAccess = Access::required(initialAccess); SecPointer<KeyItem> item = KeyItem::generateWithAttributes(attrList, keychain, algorithm, keySizeInBits, contextHandle, keyUsage, keyAttr, theAccess); // Return the generated key. if (keyRef) *keyRef = item->handle(); END_SECAPI }
/*! */ OSStatus SecACLCreateFromSimpleContents(SecAccessRef accessRef, CFArrayRef applicationList, CFStringRef description, const CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR *promptSelector, SecACLRef *newAcl) { BEGIN_SECAPI SecPointer<Access> access = Access::required(accessRef); SecPointer<ACL> acl = new ACL(cfString(description), *promptSelector); if (applicationList) { // application-list + prompt acl->form(ACL::appListForm); setApplications(acl, applicationList); } else { // allow-any acl->form(ACL::allowAllForm); } access->add(acl.get()); Required(newAcl) = acl->handle(); END_SECAPI }
Item KeyItem::importTo(const Keychain &keychain, Access *newAccess, SecKeychainAttributeList *attrList) { if (!(keychain->database()->dl()->subserviceMask() & CSSM_SERVICE_CSP)) MacOSError::throwMe(errSecInvalidKeychain); /* Get the destination keychain's db. */ SSDbImpl* dbImpl = dynamic_cast<SSDbImpl*>(&(*keychain->database())); if (dbImpl == NULL) CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER); SSDb ssDb(dbImpl); /* Make sure mKey is valid. */ /* We can't call key() here, since we won't have a unique record id yet */ if (!mKey) CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER); // Generate a random label to use initially CssmClient::CSP appleCsp(gGuidAppleCSP); CssmClient::Random random(appleCsp, CSSM_ALGID_APPLE_YARROW); uint8 labelBytes[20]; CssmData label(labelBytes, sizeof(labelBytes)); random.generate(label, label.Length); /* Set up the ACL for the new key. */ SecPointer<Access> access; if (newAccess) access = newAccess; else access = new Access(*mKey); /* Generate a random 3DES wrapping Key. */ CssmClient::GenerateKey genKey(csp(), CSSM_ALGID_3DES_3KEY, 192); CssmClient::Key wrappingKey(genKey(KeySpec(CSSM_KEYUSE_WRAP | CSSM_KEYUSE_UNWRAP, CSSM_KEYATTR_EXTRACTABLE /* | CSSM_KEYATTR_RETURN_DATA */))); /* make a random IV */ uint8 ivBytes[8]; CssmData iv(ivBytes, sizeof(ivBytes)); random.generate(iv, iv.length()); /* Extract the key by wrapping it with the wrapping key. */ CssmClient::WrapKey wrap(csp(), CSSM_ALGID_3DES_3KEY_EDE); wrap.key(wrappingKey); wrap.cred(getCredentials(CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED, kSecCredentialTypeDefault)); wrap.mode(CSSM_ALGMODE_ECBPad); wrap.padding(CSSM_PADDING_PKCS7); wrap.initVector(iv); CssmClient::Key wrappedKey(wrap(mKey)); /* Unwrap the new key into the new Keychain. */ CssmClient::UnwrapKey unwrap(keychain->csp(), CSSM_ALGID_3DES_3KEY_EDE); unwrap.key(wrappingKey); unwrap.mode(CSSM_ALGMODE_ECBPad); unwrap.padding(CSSM_PADDING_PKCS7); unwrap.initVector(iv); /* Setup the dldbHandle in the context. */ unwrap.add(CSSM_ATTRIBUTE_DL_DB_HANDLE, ssDb->handle()); /* Set up an initial aclEntry so we can change it after the unwrap. */ Access::Maker maker(Allocator::standard(), Access::Maker::kAnyMakerType); ResourceControlContext rcc; maker.initialOwner(rcc, NULL); unwrap.owner(rcc.input()); /* Unwrap the key. */ uint32 usage = mKey->usage(); /* Work around csp brokeness where it sets all usage bits in the Keyheader when CSSM_KEYUSE_ANY is set. */ if (usage & CSSM_KEYUSE_ANY) usage = CSSM_KEYUSE_ANY; CssmClient::Key unwrappedKey(unwrap(wrappedKey, KeySpec(usage, (mKey->attributes() | CSSM_KEYATTR_PERMANENT) & ~(CSSM_KEYATTR_ALWAYS_SENSITIVE | CSSM_KEYATTR_NEVER_EXTRACTABLE), label))); /* Look up unwrapped key in the DLDB. */ DbUniqueRecord uniqueId; SSDbCursor dbCursor(ssDb, 1); dbCursor->recordType(recordType()); dbCursor->add(CSSM_DB_EQUAL, kInfoKeyLabel, label); CssmClient::Key copiedKey; if (!dbCursor->nextKey(NULL, copiedKey, uniqueId)) MacOSError::throwMe(errSecItemNotFound); // Set the initial label, application label, and application tag (if provided) if (attrList) { DbAttributes newDbAttributes; SSDbCursor otherDbCursor(ssDb, 1); otherDbCursor->recordType(recordType()); bool checkForDuplicates = false; for (UInt32 index=0; index < attrList->count; index++) { SecKeychainAttribute attr = attrList->attr[index]; CssmData attrData(attr.data, attr.length); if (attr.tag == kSecKeyPrintName) { newDbAttributes.add(kInfoKeyPrintName, attrData); } if (attr.tag == kSecKeyLabel) { newDbAttributes.add(kInfoKeyLabel, attrData); otherDbCursor->add(CSSM_DB_EQUAL, kInfoKeyLabel, attrData); checkForDuplicates = true; } if (attr.tag == kSecKeyApplicationTag) { newDbAttributes.add(kInfoKeyApplicationTag, attrData); otherDbCursor->add(CSSM_DB_EQUAL, kInfoKeyApplicationTag, attrData); checkForDuplicates = true; } } DbAttributes otherDbAttributes; DbUniqueRecord otherUniqueId; CssmClient::Key otherKey; try { if (checkForDuplicates && otherDbCursor->nextKey(&otherDbAttributes, otherKey, otherUniqueId)) MacOSError::throwMe(errSecDuplicateItem); uniqueId->modify(recordType(), &newDbAttributes, NULL, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE); } catch (CssmError e) { // clean up after trying to insert a duplicate key uniqueId->deleteRecord (); throw; } } /* Set the acl and owner on the unwrapped key. */ access->setAccess(*unwrappedKey, maker); /* Return a keychain item which represents the new key. */ Item item(keychain->item(recordType(), uniqueId)); KCEventNotifier::PostKeychainEvent(kSecAddEvent, keychain, item); return item; }
SecPointer<KeyItem> KeyItem::generateWithAttributes(const SecKeychainAttributeList *attrList, Keychain keychain, CSSM_ALGORITHMS algorithm, uint32 keySizeInBits, CSSM_CC_HANDLE contextHandle, CSSM_KEYUSE keyUsage, uint32 keyAttr, SecPointer<Access> initialAccess) { CssmClient::CSP appleCsp(gGuidAppleCSP); CssmClient::CSP csp(NULL); SSDb ssDb(NULL); uint8 labelBytes[20]; CssmData label(labelBytes, sizeof(labelBytes)); bool freeKey = false; bool deleteContext = false; const CSSM_DATA *plabel = NULL; if (keychain) { if (!(keychain->database()->dl()->subserviceMask() & CSSM_SERVICE_CSP)) MacOSError::throwMe(errSecInvalidKeychain); SSDbImpl* impl = dynamic_cast<SSDbImpl *>(&(*keychain->database())); if (impl == NULL) { CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER); } ssDb = SSDb(impl); csp = keychain->csp(); // Generate a random label to use initially CssmClient::Random random(appleCsp, CSSM_ALGID_APPLE_YARROW); random.generate(label, label.Length); plabel = &label; } else { // Not a persistent key so create it in the regular csp csp = appleCsp; } // Create a Access::Maker for the initial owner of the private key. ResourceControlContext *prcc = NULL, rcc; const AccessCredentials *cred = NULL; Access::Maker maker; if (keychain && initialAccess) { memset(&rcc, 0, sizeof(rcc)); // @@@ Potentially provide a credential argument which allows us to generate keys in the csp. // Currently the CSP lets anyone do this, but we might restrict this in the future, e.g. a smartcard // could require out-of-band pin entry before a key can be generated. maker.initialOwner(rcc); // Create the cred we need to manipulate the keys until we actually set a new access control for them. cred = maker.cred(); prcc = &rcc; } CSSM_KEY cssmKey; CSSM_CC_HANDLE ccHandle = 0; Item keyItem; try { CSSM_RETURN status; if (contextHandle) ccHandle = contextHandle; else { status = CSSM_CSP_CreateKeyGenContext(csp->handle(), algorithm, keySizeInBits, NULL, NULL, NULL, NULL, NULL, &ccHandle); if (status) CssmError::throwMe(status); deleteContext = true; } if (ssDb) { CSSM_DL_DB_HANDLE dldbHandle = ssDb->handle(); CSSM_DL_DB_HANDLE_PTR dldbHandlePtr = &dldbHandle; CSSM_CONTEXT_ATTRIBUTE contextAttributes = { CSSM_ATTRIBUTE_DL_DB_HANDLE, sizeof(dldbHandle), { (char *)dldbHandlePtr } }; status = CSSM_UpdateContextAttributes(ccHandle, 1, &contextAttributes); if (status) CssmError::throwMe(status); keyAttr |= CSSM_KEYATTR_PERMANENT; } // Generate the key status = CSSM_GenerateKey(ccHandle, keyUsage, keyAttr, plabel, prcc, &cssmKey); if (status) CssmError::throwMe(status); if (ssDb) { freeKey = true; // Find the key we just generated in the DL and get a SecKeyRef // so we can specify the label attribute(s) and initial ACL. // Look up key in the DLDB. DbAttributes dbAttributes; DbUniqueRecord uniqueId; SSDbCursor dbCursor(ssDb, 1); dbCursor->recordType(CSSM_DL_DB_RECORD_SYMMETRIC_KEY); dbCursor->add(CSSM_DB_EQUAL, kInfoKeyLabel, label); CssmClient::Key key; if (!dbCursor->nextKey(&dbAttributes, key, uniqueId)) MacOSError::throwMe(errSecItemNotFound); // Set the initial label, application label, and application tag (if provided) if (attrList) { DbAttributes newDbAttributes; SSDbCursor otherDbCursor(ssDb, 1); otherDbCursor->recordType(CSSM_DL_DB_RECORD_SYMMETRIC_KEY); bool checkForDuplicates = false; for (UInt32 index=0; index < attrList->count; index++) { SecKeychainAttribute attr = attrList->attr[index]; CssmData attrData(attr.data, attr.length); if (attr.tag == kSecKeyPrintName) { newDbAttributes.add(kInfoKeyPrintName, attrData); } if (attr.tag == kSecKeyLabel) { newDbAttributes.add(kInfoKeyLabel, attrData); otherDbCursor->add(CSSM_DB_EQUAL, kInfoKeyLabel, attrData); checkForDuplicates = true; } if (attr.tag == kSecKeyApplicationTag) { newDbAttributes.add(kInfoKeyApplicationTag, attrData); otherDbCursor->add(CSSM_DB_EQUAL, kInfoKeyApplicationTag, attrData); checkForDuplicates = true; } } DbAttributes otherDbAttributes; DbUniqueRecord otherUniqueId; CssmClient::Key otherKey; if (checkForDuplicates && otherDbCursor->nextKey(&otherDbAttributes, otherKey, otherUniqueId)) MacOSError::throwMe(errSecDuplicateItem); uniqueId->modify(CSSM_DL_DB_RECORD_SYMMETRIC_KEY, &newDbAttributes, NULL, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE); } // Finally, fix the acl and owner of the key to the specified access control settings. if (initialAccess) initialAccess->setAccess(*key, maker); // Create keychain item which will represent the key. keyItem = keychain->item(CSSM_DL_DB_RECORD_SYMMETRIC_KEY, uniqueId); } else { CssmClient::Key tempKey(csp, cssmKey); keyItem = new KeyItem(tempKey); } } catch (...) { if (freeKey) { // Delete the key if something goes wrong so we don't end up with inaccessible keys in the database. CSSM_FreeKey(csp->handle(), cred, &cssmKey, TRUE); } if (deleteContext) CSSM_DeleteContext(ccHandle); throw; } if (freeKey) { CSSM_FreeKey(csp->handle(), NULL, &cssmKey, FALSE); } if (deleteContext) CSSM_DeleteContext(ccHandle); if (keychain && keyItem) keychain->postEvent(kSecAddEvent, keyItem); KeyItem* item = dynamic_cast<KeyItem*>(&*keyItem); if (item == NULL) { CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER); } return item; }
void KeyItem::importPair( Keychain keychain, const CSSM_KEY &publicWrappedKey, const CSSM_KEY &privateWrappedKey, SecPointer<Access> initialAccess, SecPointer<KeyItem> &outPublicKey, SecPointer<KeyItem> &outPrivateKey) { bool freePublicKey = false; bool freePrivateKey = false; bool deleteContext = false; if (!(keychain->database()->dl()->subserviceMask() & CSSM_SERVICE_CSP)) MacOSError::throwMe(errSecInvalidKeychain); SSDbImpl* impl = dynamic_cast<SSDbImpl *>(&(*keychain->database())); if (impl == NULL) { CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER); } SSDb ssDb(impl); CssmClient::CSP csp(keychain->csp()); CssmClient::CSP appleCsp(gGuidAppleCSP); // Create a Access::Maker for the initial owner of the private key. ResourceControlContext rcc; memset(&rcc, 0, sizeof(rcc)); Access::Maker maker(Allocator::standard(), Access::Maker::kAnyMakerType); // @@@ Potentially provide a credential argument which allows us to unwrap keys in the csp. // Currently the CSP lets anyone do this, but we might restrict this in the future, e.g. // a smartcard could require out of band pin entry before a key can be generated. maker.initialOwner(rcc); // Create the cred we need to manipulate the keys until we actually set a new access control for them. const AccessCredentials *cred = maker.cred(); CSSM_KEY publicCssmKey, privateCssmKey; memset(&publicCssmKey, 0, sizeof(publicCssmKey)); memset(&privateCssmKey, 0, sizeof(privateCssmKey)); CSSM_CC_HANDLE ccHandle = 0; Item publicKeyItem, privateKeyItem; try { CSSM_RETURN status; // Calculate the hash of the public key using the appleCSP. CssmClient::PassThrough passThrough(appleCsp); void *outData; CssmData *cssmData; /* Given a CSSM_KEY_PTR in any format, obtain the SHA-1 hash of the * associated key blob. * Key is specified in CSSM_CSP_CreatePassThroughContext. * Hash is allocated bythe CSP, in the App's memory, and returned * in *outData. */ passThrough.key(&publicWrappedKey); passThrough(CSSM_APPLECSP_KEYDIGEST, NULL, &outData); cssmData = reinterpret_cast<CssmData *>(outData); CssmData &pubKeyHash = *cssmData; status = CSSM_CSP_CreateSymmetricContext(csp->handle(), publicWrappedKey.KeyHeader.WrapAlgorithmId, CSSM_ALGMODE_NONE, NULL, NULL, NULL, CSSM_PADDING_NONE, NULL, &ccHandle); if (status) CssmError::throwMe(status); deleteContext = true; CSSM_DL_DB_HANDLE dldbHandle = ssDb->handle(); CSSM_DL_DB_HANDLE_PTR dldbHandlePtr = &dldbHandle; CSSM_CONTEXT_ATTRIBUTE contextAttributes = { CSSM_ATTRIBUTE_DL_DB_HANDLE, sizeof(dldbHandle), { (char *)dldbHandlePtr } }; status = CSSM_UpdateContextAttributes(ccHandle, 1, &contextAttributes); if (status) CssmError::throwMe(status); // Unwrap the the keys CSSM_DATA descriptiveData = {0, NULL}; status = CSSM_UnwrapKey( ccHandle, NULL, &publicWrappedKey, publicWrappedKey.KeyHeader.KeyUsage, publicWrappedKey.KeyHeader.KeyAttr | CSSM_KEYATTR_PERMANENT, &pubKeyHash, &rcc, &publicCssmKey, &descriptiveData); if (status) CssmError::throwMe(status); freePublicKey = true; if (descriptiveData.Data != NULL) free (descriptiveData.Data); status = CSSM_UnwrapKey( ccHandle, NULL, &privateWrappedKey, privateWrappedKey.KeyHeader.KeyUsage, privateWrappedKey.KeyHeader.KeyAttr | CSSM_KEYATTR_PERMANENT, &pubKeyHash, &rcc, &privateCssmKey, &descriptiveData); if (status) CssmError::throwMe(status); if (descriptiveData.Data != NULL) free (descriptiveData.Data); freePrivateKey = true; // Find the keys we just generated in the DL to get SecKeyRefs to them // so we can change the label to be the hash of the public key, and // fix up other attributes. // Look up public key in the DLDB. DbAttributes pubDbAttributes; DbUniqueRecord pubUniqueId; SSDbCursor dbPubCursor(ssDb, 1); dbPubCursor->recordType(CSSM_DL_DB_RECORD_PUBLIC_KEY); dbPubCursor->add(CSSM_DB_EQUAL, kInfoKeyLabel, pubKeyHash); CssmClient::Key publicKey; if (!dbPubCursor->nextKey(&pubDbAttributes, publicKey, pubUniqueId)) MacOSError::throwMe(errSecItemNotFound); // Look up private key in the DLDB. DbAttributes privDbAttributes; DbUniqueRecord privUniqueId; SSDbCursor dbPrivCursor(ssDb, 1); dbPrivCursor->recordType(CSSM_DL_DB_RECORD_PRIVATE_KEY); dbPrivCursor->add(CSSM_DB_EQUAL, kInfoKeyLabel, pubKeyHash); CssmClient::Key privateKey; if (!dbPrivCursor->nextKey(&privDbAttributes, privateKey, privUniqueId)) MacOSError::throwMe(errSecItemNotFound); // @@@ Not exception safe! csp.allocator().free(cssmData->Data); csp.allocator().free(cssmData); auto_ptr<string>privDescription; auto_ptr<string>pubDescription; try { privDescription.reset(new string(initialAccess->promptDescription())); pubDescription.reset(new string(initialAccess->promptDescription())); } catch(...) { /* this path taken if no promptDescription available, e.g., for complex ACLs */ privDescription.reset(new string("Private key")); pubDescription.reset(new string("Public key")); } // Set the label of the public key to the public key hash. // Set the PrintName of the public key to the description in the acl. pubDbAttributes.add(kInfoKeyPrintName, *pubDescription); pubUniqueId->modify(CSSM_DL_DB_RECORD_PUBLIC_KEY, &pubDbAttributes, NULL, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE); // Set the label of the private key to the public key hash. // Set the PrintName of the private key to the description in the acl. privDbAttributes.add(kInfoKeyPrintName, *privDescription); privUniqueId->modify(CSSM_DL_DB_RECORD_PRIVATE_KEY, &privDbAttributes, NULL, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE); // Finally fix the acl and owner of the private key to the specified access control settings. initialAccess->setAccess(*privateKey, maker); // Make the public key acl completely open SecPointer<Access> pubKeyAccess(new Access()); pubKeyAccess->setAccess(*publicKey, maker); // Create keychain items which will represent the keys. publicKeyItem = keychain->item(CSSM_DL_DB_RECORD_PUBLIC_KEY, pubUniqueId); privateKeyItem = keychain->item(CSSM_DL_DB_RECORD_PRIVATE_KEY, privUniqueId); KeyItem* impl = dynamic_cast<KeyItem*>(&(*publicKeyItem)); if (impl == NULL) { CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER); } outPublicKey = impl; impl = dynamic_cast<KeyItem*>(&(*privateKeyItem)); if (impl == NULL) { CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER); } outPrivateKey = impl; } catch (...) { if (freePublicKey) CSSM_FreeKey(csp->handle(), cred, &publicCssmKey, TRUE); if (freePrivateKey) CSSM_FreeKey(csp->handle(), cred, &privateCssmKey, TRUE); if (deleteContext) CSSM_DeleteContext(ccHandle); throw; } if (freePublicKey) CSSM_FreeKey(csp->handle(), cred, &publicCssmKey, FALSE); if (freePrivateKey) CSSM_FreeKey(csp->handle(), cred, &privateCssmKey, FALSE); if (deleteContext) CSSM_DeleteContext(ccHandle); if (keychain && publicKeyItem && privateKeyItem) { KCEventNotifier::PostKeychainEvent(kSecAddEvent, keychain, publicKeyItem); KCEventNotifier::PostKeychainEvent(kSecAddEvent, keychain, privateKeyItem); } }
bool IdentityCursorPolicyAndID::next(SecPointer<Identity> &identity) { SecPointer<Identity> currIdentity; Boolean identityOK = true; if (!mPreferredIdentityChecked) { try { findPreferredIdentity(); } catch(...) {} mPreferredIdentityChecked = true; if (mPreferredIdentity) { identity = mPreferredIdentity; return true; } } for (;;) { bool result = IdentityCursor::next(currIdentity); // base class finds the next identity by keyUsage if ( result ) { if (mPreferredIdentity && (currIdentity == mPreferredIdentity)) { identityOK = false; // we already returned this one, move on to the next continue; } // If there was no policy specified, we're done. if ( !mPolicy ) { identityOK = true; // return this identity break; } // To reduce the number of (potentially expensive) trust evaluations performed, we need // to do some pre-processing to filter out certs that don't match the search criteria. // Rather than try to duplicate the TP's policy logic here, we'll just call the TP with // a single-element certificate array, no anchors, and no keychains to search. SecPointer<Certificate> certificate = currIdentity->certificate(); CFRef<SecCertificateRef> certRef(certificate->handle()); CFRef<CFMutableArrayRef> anchorsArray(CFArrayCreateMutable(NULL, 1, NULL)); CFRef<CFMutableArrayRef> certArray(CFArrayCreateMutable(NULL, 1, NULL)); if ( !certArray || !anchorsArray ) { identityOK = false; // skip this and move on to the next one continue; } CFArrayAppendValue(certArray, certRef); SecPointer<Trust> trustLite = new Trust(certArray, mPolicy); StorageManager::KeychainList emptyList; // Set the anchors and keychain search list to be empty trustLite->anchors(anchorsArray); trustLite->searchLibs(emptyList); trustLite->evaluate(); SecTrustResultType trustResult = trustLite->result(); if (trustResult == kSecTrustResultRecoverableTrustFailure || trustResult == kSecTrustResultFatalTrustFailure) { CFArrayRef certChain = NULL; CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL, *evInfo = NULL; trustLite->buildEvidence(certChain, TPEvidenceInfo::overlayVar(statusChain)); if (statusChain) evInfo = &statusChain[0]; if (!evInfo || evInfo->NumStatusCodes > 0) // per-cert codes means we can't use this cert for this policy trustResult = kSecTrustResultInvalid; // handled below if (certChain) CFRelease(certChain); } if (trustResult == kSecTrustResultInvalid) { identityOK = false; // move on to the next one continue; } // If trust evaluation isn't requested, we're done. if ( !mReturnOnlyValidIdentities ) { identityOK = true; // return this identity break; } // Perform a full trust evaluation on the certificate with the specified policy. SecPointer<Trust> trust = new Trust(certArray, mPolicy); trust->evaluate(); trustResult = trust->result(); if (trustResult == kSecTrustResultInvalid || trustResult == kSecTrustResultRecoverableTrustFailure || trustResult == kSecTrustResultFatalTrustFailure) { identityOK = false; // move on to the next one continue; } identityOK = true; // this one was OK; return it. break; } else { identityOK = false; // no more left. break; } } // for(;;) if ( identityOK ) { identity = currIdentity; // caller will release the identity return true; } else { return false; } }
void KeyItem::createPair( Keychain keychain, CSSM_ALGORITHMS algorithm, uint32 keySizeInBits, CSSM_CC_HANDLE contextHandle, CSSM_KEYUSE publicKeyUsage, uint32 publicKeyAttr, CSSM_KEYUSE privateKeyUsage, uint32 privateKeyAttr, SecPointer<Access> initialAccess, SecPointer<KeyItem> &outPublicKey, SecPointer<KeyItem> &outPrivateKey) { bool freeKeys = false; bool deleteContext = false; if (!(keychain->database()->dl()->subserviceMask() & CSSM_SERVICE_CSP)) MacOSError::throwMe(errSecInvalidKeychain); SSDbImpl* impl = dynamic_cast<SSDbImpl*>(&(*keychain->database())); if (impl == NULL) { CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER); } SSDb ssDb(impl); CssmClient::CSP csp(keychain->csp()); CssmClient::CSP appleCsp(gGuidAppleCSP); // Generate a random label to use initially CssmClient::Random random(appleCsp, CSSM_ALGID_APPLE_YARROW); uint8 labelBytes[20]; CssmData label(labelBytes, sizeof(labelBytes)); random.generate(label, label.Length); // Create a Access::Maker for the initial owner of the private key. ResourceControlContext rcc; memset(&rcc, 0, sizeof(rcc)); Access::Maker maker; // @@@ 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. maker.initialOwner(rcc); // Create the cred we need to manipulate the keys until we actually set a new access control for them. const AccessCredentials *cred = maker.cred(); CSSM_KEY publicCssmKey, privateCssmKey; memset(&publicCssmKey, 0, sizeof(publicCssmKey)); memset(&privateCssmKey, 0, sizeof(privateCssmKey)); CSSM_CC_HANDLE ccHandle = 0; Item publicKeyItem, privateKeyItem; try { CSSM_RETURN status; if (contextHandle) ccHandle = contextHandle; else { status = CSSM_CSP_CreateKeyGenContext(csp->handle(), algorithm, keySizeInBits, NULL, NULL, NULL, NULL, NULL, &ccHandle); if (status) CssmError::throwMe(status); deleteContext = true; } CSSM_DL_DB_HANDLE dldbHandle = ssDb->handle(); CSSM_DL_DB_HANDLE_PTR dldbHandlePtr = &dldbHandle; CSSM_CONTEXT_ATTRIBUTE contextAttributes = { CSSM_ATTRIBUTE_DL_DB_HANDLE, sizeof(dldbHandle), { (char *)dldbHandlePtr } }; status = CSSM_UpdateContextAttributes(ccHandle, 1, &contextAttributes); if (status) CssmError::throwMe(status); // Generate the keypair status = CSSM_GenerateKeyPair(ccHandle, publicKeyUsage, publicKeyAttr, &label, &publicCssmKey, privateKeyUsage, privateKeyAttr, &label, &rcc, &privateCssmKey); if (status) CssmError::throwMe(status); freeKeys = true; // Find the keys we just generated in the DL to get SecKeyRef's to them // so we can change the label to be the hash of the public key, and // fix up other attributes. // Look up public key in the DLDB. DbAttributes pubDbAttributes; DbUniqueRecord pubUniqueId; SSDbCursor dbPubCursor(ssDb, 1); dbPubCursor->recordType(CSSM_DL_DB_RECORD_PUBLIC_KEY); dbPubCursor->add(CSSM_DB_EQUAL, kInfoKeyLabel, label); CssmClient::Key publicKey; if (!dbPubCursor->nextKey(&pubDbAttributes, publicKey, pubUniqueId)) MacOSError::throwMe(errSecItemNotFound); // Look up private key in the DLDB. DbAttributes privDbAttributes; DbUniqueRecord privUniqueId; SSDbCursor dbPrivCursor(ssDb, 1); dbPrivCursor->recordType(CSSM_DL_DB_RECORD_PRIVATE_KEY); dbPrivCursor->add(CSSM_DB_EQUAL, kInfoKeyLabel, label); CssmClient::Key privateKey; if (!dbPrivCursor->nextKey(&privDbAttributes, privateKey, privUniqueId)) MacOSError::throwMe(errSecItemNotFound); // Convert reference public key to a raw key so we can use it // in the appleCsp. CssmClient::WrapKey wrap(csp, CSSM_ALGID_NONE); wrap.cred(cred); CssmClient::Key rawPubKey = wrap(publicKey); // Calculate the hash of the public key using the appleCSP. CssmClient::PassThrough passThrough(appleCsp); void *outData; CssmData *cssmData; /* Given a CSSM_KEY_PTR in any format, obtain the SHA-1 hash of the * associated key blob. * Key is specified in CSSM_CSP_CreatePassThroughContext. * Hash is allocated bythe CSP, in the App's memory, and returned * in *outData. */ passThrough.key(rawPubKey); passThrough(CSSM_APPLECSP_KEYDIGEST, NULL, &outData); cssmData = reinterpret_cast<CssmData *>(outData); CssmData &pubKeyHash = *cssmData; auto_ptr<string>privDescription; auto_ptr<string>pubDescription; try { privDescription.reset(new string(initialAccess->promptDescription())); pubDescription.reset(new string(initialAccess->promptDescription())); } catch(...) { /* this path taken if no promptDescription available, e.g., for complex ACLs */ privDescription.reset(new string("Private key")); pubDescription.reset(new string("Public key")); } // Set the label of the public key to the public key hash. // Set the PrintName of the public key to the description in the acl. pubDbAttributes.add(kInfoKeyLabel, pubKeyHash); pubDbAttributes.add(kInfoKeyPrintName, *pubDescription); pubUniqueId->modify(CSSM_DL_DB_RECORD_PUBLIC_KEY, &pubDbAttributes, NULL, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE); // Set the label of the private key to the public key hash. // Set the PrintName of the private key to the description in the acl. privDbAttributes.add(kInfoKeyLabel, pubKeyHash); privDbAttributes.add(kInfoKeyPrintName, *privDescription); privUniqueId->modify(CSSM_DL_DB_RECORD_PRIVATE_KEY, &privDbAttributes, NULL, CSSM_DB_MODIFY_ATTRIBUTE_REPLACE); // @@@ Not exception safe! csp.allocator().free(cssmData->Data); csp.allocator().free(cssmData); // Finally fix the acl and owner of the private key to the specified access control settings. initialAccess->setAccess(*privateKey, maker); if(publicKeyAttr & CSSM_KEYATTR_PUBLIC_KEY_ENCRYPT) { /* * Make the public key acl completely open. * If the key was not encrypted, it already has a wide-open * ACL (though that is a feature of securityd; it's not * CDSA-specified behavior). */ SecPointer<Access> pubKeyAccess(new Access()); pubKeyAccess->setAccess(*publicKey, maker); } // Create keychain items which will represent the keys. publicKeyItem = keychain->item(CSSM_DL_DB_RECORD_PUBLIC_KEY, pubUniqueId); privateKeyItem = keychain->item(CSSM_DL_DB_RECORD_PRIVATE_KEY, privUniqueId); KeyItem* impl = dynamic_cast<KeyItem*>(&(*publicKeyItem)); if (impl == NULL) { CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER); } outPublicKey = impl; impl = dynamic_cast<KeyItem*>(&(*privateKeyItem)); if (impl == NULL) { CssmError::throwMe(CSSMERR_CSSM_INVALID_POINTER); } outPrivateKey = impl; } catch (...) { if (freeKeys) { // Delete the keys if something goes wrong so we don't end up with inaccessible keys in the database. CSSM_FreeKey(csp->handle(), cred, &publicCssmKey, TRUE); CSSM_FreeKey(csp->handle(), cred, &privateCssmKey, TRUE); } if (deleteContext) CSSM_DeleteContext(ccHandle); throw; } if (freeKeys) { CSSM_FreeKey(csp->handle(), NULL, &publicCssmKey, FALSE); CSSM_FreeKey(csp->handle(), NULL, &privateCssmKey, FALSE); } if (deleteContext) CSSM_DeleteContext(ccHandle); if (keychain && publicKeyItem && privateKeyItem) { keychain->postEvent(kSecAddEvent, publicKeyItem); keychain->postEvent(kSecAddEvent, privateKeyItem); } }