/* * Search specified keychain/array/NULL (NULL meaning the default search list) for * an Identity matching specified key usage and optional Issuer/Serial number. * If issuer/serial is specified and no identities match, or if no identities found * matching specified Key usage, errSecItemNotFound is returned. * * Caller must CFRelease a non-NULL returned idRef. */ static OSStatus pkinit_search_ident( CFTypeRef keychainOrArray, CSSM_KEYUSE keyUsage, const CSSM_DATA *issuerSerial, /* optional */ SecIdentityRef *foundId) /* RETURNED */ { OSStatus ortn; SecIdentityRef idRef = NULL; SecIdentitySearchRef srchRef = NULL; ortn = SecIdentitySearchCreate(keychainOrArray, keyUsage, &srchRef); if(ortn) { pkiCssmErr("SecIdentitySearchCreate", ortn); return ortn; } do { ortn = SecIdentitySearchCopyNext(srchRef, &idRef); if(ortn != noErr) { break; } if(issuerSerial == NULL) { /* no match needed, we're done - this is the KDC cert case */ break; } else if(pkinit_issuer_sn_match(idRef, issuerSerial)) { /* match, we're done */ break; } /* finished with this one */ CFRelease(idRef); idRef = NULL; } while(ortn == noErr); CFRelease(srchRef); if(idRef == NULL) { return errSecItemNotFound; } else { *foundId = idRef; return noErr; } }
/* * Add all SecIdentityRefs from a keychain into an array. */ static OSStatus addIdentities( SecKeychainRef kcRef, CFMutableArrayRef outArray, unsigned *numItems) // UPDATED on return { /* Search for all identities */ SecIdentitySearchRef srchRef; OSStatus ortn = SecIdentitySearchCreate(kcRef, 0, // keyUsage - any &srchRef); if(ortn) { sec_perror("SecIdentitySearchCreate", ortn); return ortn; } do { SecIdentityRef identity; ortn = SecIdentitySearchCopyNext(srchRef, &identity); if(ortn) { if(ortn == errSecItemNotFound) { /* normal search end */ ortn = noErr; } else { sec_perror("SecIdentitySearchCopyNext", ortn); } break; } CFArrayAppendValue(outArray, identity); /* the array has the retain count we need */ CFRelease(identity); (*numItems)++; } while(ortn == noErr); CFRelease(srchRef); return ortn; }
int findEncryptionIdentities(CFTypeRef *identityOrArray) { /* Similar code is available in Leopard9A311 and later as "DIHLFVCopyEncryptionIdentities". See <rdar://problem/4816811> FV: Add SecTokenBasedEncryptionIdentities call We reproduce it here for two reasons: 1) The semantics of DIHLFVCopyEncryptionIdentities are different, returning either a CFData or CFArray 2) We don' have to introduce a dependence on DiskImages.framework here Since CSSM searching for attributes is an AND, not an OR, we need to get all identities then check each one for a good key usage. If we built up a search using an OR predicate, we would want to specify this for key usage: uint32_t keyuse = CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_WRAP | CSSM_KEYUSE_UNWRAP; */ OSStatus status = noErr; CFArrayRef searchList = NULL; CFMutableArrayRef idArray = NULL; // holds all SecIdentityRefs found status = SecKeychainCopyDomainSearchList(kSecPreferencesDomainDynamic, &searchList); if (status) return status; CFIndex count = searchList ? CFArrayGetCount(searchList) : 0; if (!count) return errSecNoSuchKeychain; // Search for all identities uint32_t keyuse = 0; SecIdentitySearchRef srchRef = NULL; status = SecIdentitySearchCreate(searchList, keyuse, &srchRef); if (status) return status; while (!status) { SecIdentityRef identity = NULL; status = SecIdentitySearchCopyNext(srchRef, &identity); if (status == errSecItemNotFound) // done break; if (status) return status; SecKeyRef privateKeyRef = NULL; status = SecIdentityCopyPrivateKey(identity, &privateKeyRef); if (status) continue; bool canEncrypt = encryptionEnabled(privateKeyRef); CFRelease(privateKeyRef); if (!canEncrypt) continue; // add the identity to the array if (!idArray) idArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); CFArrayAppendValue(idArray, identity); } if ((status == noErr || status == errSecItemNotFound) && idArray && CFArrayGetCount(idArray)) { if (idArray) { *identityOrArray = idArray; ::CFRetain(*identityOrArray); } status = noErr; } else if (idArray) CFRelease(idArray); return status; }
/* * Given an open keychain, find a SecIdentityRef and munge it into * a CFArrayRef required by SSLSetCertificate(). */ CFArrayRef sslKcRefToCertArray( SecKeychainRef kcRef, bool encryptOnly, bool completeCertChain, const char *trustedAnchorFile) { /* quick check to make sure the keychain exists */ SecKeychainStatus kcStat; OSStatus ortn = SecKeychainGetStatus(kcRef, &kcStat); if(ortn) { printSslErrStr("SecKeychainGetStatus", ortn); printf("Can not open keychain. Aborting.\n"); return nil; } /* * Search for "any" identity matching specified key use; * in this app, we expect there to be exactly one. */ SecIdentitySearchRef srchRef = nil; ortn = SecIdentitySearchCreate(kcRef, encryptOnly ? CSSM_KEYUSE_DECRYPT : CSSM_KEYUSE_SIGN, &srchRef); if(ortn) { printf("SecIdentitySearchCreate returned %d.\n", (int)ortn); printf("Cannot find signing key in keychain. Aborting.\n"); return nil; } SecIdentityRef identity = nil; ortn = SecIdentitySearchCopyNext(srchRef, &identity); if(ortn) { printf("SecIdentitySearchCopyNext returned %d.\n", (int)ortn); printf("Cannot find signing key in keychain. Aborting.\n"); return nil; } if(CFGetTypeID(identity) != SecIdentityGetTypeID()) { printf("SecIdentitySearchCopyNext CFTypeID failure!\n"); return nil; } /* * Found one. */ if(completeCertChain) { /* * Place it and the other certs needed to verify it - * up to but not including the root - in a CFArray. */ SecCertificateRef anchorCert = NULL; if(trustedAnchorFile) { ortn = sslReadAnchor(trustedAnchorFile, &anchorCert); if(ortn) { printf("***Error reading anchor file\n"); } } CFArrayRef ca; ortn = sslCompleteCertChain(identity, anchorCert, false, &ca); if(anchorCert) { CFRelease(anchorCert); } return ca; } else { /* simple case, just this one identity */ CFArrayRef ca = CFArrayCreate(NULL, (const void **)&identity, 1, NULL); if(ca == nil) { printf("CFArrayCreate error\n"); } return ca; } }