static OSStatus _SecIdentityCopyPreferenceMatchingName( CFStringRef name, CSSM_KEYUSE keyUsage, CFArrayRef validIssuers, SecIdentityRef *identity) { // this is NOT exported, and called only from SecIdentityCopyPreference (below), so no BEGIN/END macros here; // caller must handle exceptions StorageManager::KeychainList keychains; globals().storageManager.getSearchList(keychains); KCCursor cursor(keychains, kSecGenericPasswordItemClass, NULL); char idUTF8[MAXPATHLEN]; Required(name); if (!CFStringGetCString(name, idUTF8, sizeof(idUTF8)-1, kCFStringEncodingUTF8)) idUTF8[0] = (char)'\0'; CssmData service(const_cast<char *>(idUTF8), strlen(idUTF8)); FourCharCode itemType = 'iprf'; cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecServiceItemAttr), service); cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecTypeItemAttr), itemType); if (keyUsage) cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecScriptCodeItemAttr), (sint32)keyUsage); Item prefItem; if (!cursor->next(prefItem)) return errSecItemNotFound; // get persistent certificate reference SecKeychainAttribute itemAttrs[] = { { kSecGenericItemAttr, 0, NULL } }; SecKeychainAttributeList itemAttrList = { sizeof(itemAttrs) / sizeof(itemAttrs[0]), itemAttrs }; prefItem->getContent(NULL, &itemAttrList, NULL, NULL); // find certificate, given persistent reference data CFDataRef pItemRef = CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)itemAttrs[0].data, itemAttrs[0].length, kCFAllocatorNull); SecKeychainItemRef certItemRef = nil; OSStatus status = SecKeychainItemCopyFromPersistentReference(pItemRef, &certItemRef); //%%% need to make this a method of ItemImpl prefItem->freeContent(&itemAttrList, NULL); if (pItemRef) CFRelease(pItemRef); if (status) return status; // filter on valid issuers, if provided if (validIssuers) { //%%%TBI } // create identity reference, given certificate Item certItem = ItemImpl::required(SecKeychainItemRef(certItemRef)); SecPointer<Certificate> certificate(static_cast<Certificate *>(certItem.get())); SecPointer<Identity> identity_ptr(new Identity(keychains, certificate)); if (certItemRef) CFRelease(certItemRef); Required(identity) = identity_ptr->handle(); return status; }
OSStatus findCertificatePublicKeyHash(SecCertificateRef certificate, CFDataRef *label) { UInt32 tag[1] = { kSecPublicKeyHashItemAttr }; // kSecKeyLabel == hash public key [kSecPublicKeyHashItemAttr ??kSecKeyLabel] UInt32 format[1] = { CSSM_DB_ATTRIBUTE_FORMAT_BLOB }; SecKeychainAttributeInfo info = { 1, tag, format }; // attrs to retrieve SecKeychainAttributeList *attrList = NULL; OSStatus status = SecKeychainItemCopyAttributesAndData(SecKeychainItemRef(certificate), &info, NULL, &attrList, 0, NULL); if (status || !attrList || !attrList->count) return status; const uint32_t index = 0; if (attrList->attr[index].tag == kSecPublicKeyHashItemAttr) *label = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)attrList->attr[index].data, attrList->attr[index].length); SecKeychainItemFreeAttributesAndData(attrList, NULL); return noErr; }
// // Given a polymorphic Sec type object, return // its AclBearer component. // Note: Login ACLs are not hooked into this layer; // modules or attachments have no Sec* layer representation. // static RefPointer<AclBearer> aclBearer(CFTypeRef itemRef) { // well, exactly what kind of something are you? CFTypeID id = CFGetTypeID(itemRef); if (id == gTypes().ItemImpl.typeID) { // keychain item. If it's in a protected group, return the group key if (SSGroup group = ItemImpl::required(SecKeychainItemRef(itemRef))->group()) return &*group; } else if (id == SecKeyGetTypeID() && SecKeyIsCDSAKey((SecKeyRef)itemRef)) { // key item, return the key itself. if (CssmClient::Key key = KeyItem::required(SecKeyRef(itemRef))->key()) return &*key; } else if (id == gTypes().KeychainImpl.typeID) { // keychain (this yields the database ACL) //@@@ not hooked up yet } // Guess not. Bummer MacOSError::throwMe(errSecNoAccessForItem); }
int findFirstEncryptionPublicKeyOnToken(SecKeyRef *publicKey, SecKeychainRef *keychainRef, CFDataRef *label) { if (!publicKey || !keychainRef) return paramErr; OSStatus status = noErr; CFArrayRef identityArray = NULL; SecKeyRef tmpKeyRef = NULL; SecCertificateRef certificate = NULL; SecKeychainRef tmpKeychainRef = NULL; try { status = findEncryptionIdentities((CFTypeRef *)&identityArray); if (status) MacOSError::throwMe(status); if (!identityArray || (CFGetTypeID(identityArray)!=CFArrayGetTypeID()) || (CFArrayGetCount(identityArray)==0)) MacOSError::throwMe(paramErr); CFTypeRef tmpref = CFArrayGetValueAtIndex(identityArray, 0); if (CFGetTypeID(tmpref)!=SecIdentityGetTypeID()) MacOSError::throwMe(paramErr); status = SecIdentityCopyCertificate(SecIdentityRef(tmpref), &certificate); if (status) MacOSError::throwMe(status); if (!certificate) MacOSError::throwMe(errKCItemNotFound); status = findCertificatePublicKeyHash(certificate, label); if (status) MacOSError::throwMe(status); status = SecKeychainItemCopyKeychain(SecKeychainItemRef(certificate), &tmpKeychainRef); if (status) MacOSError::throwMe(status); status = SecCertificateCopyPublicKey(certificate, &tmpKeyRef); if (status) MacOSError::throwMe(status); // Found an encryption key *publicKey = tmpKeyRef; *keychainRef = tmpKeychainRef; } catch (const MacOSError &err) { status = err.osStatus(); cssmPerror("findFirstEncryptionPublicKeyOnToken", status); } catch (...) { fprintf(stderr, "findFirstEncryptionPublicKeyOnToken: unknown exception\n"); status = errKCItemNotFound; } if (status) { if (identityArray) CFRelease(identityArray); if (certificate) CFRelease(certificate); } if (identityArray) CFRelease(identityArray); if (certificate) CFRelease(certificate); return status; }