CFArrayRef SRCopyItems(CFArrayRef keychains, CFArrayRef classes) { CFMutableArrayRef allItems = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); CFMutableDictionaryRef query = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionarySetValue(query, kSecMatchSearchList, keychains); CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue); CFDictionarySetValue(query, kSecReturnAttributes, kCFBooleanTrue); CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll); for (int i = 0; i < CFArrayGetCount(classes); i++) { CFTypeRef class = CFArrayGetValueAtIndex(classes, i); CFDictionarySetValue(query, kSecClass, class); CFArrayRef items = NULL; OSStatus status = SecItemCopyMatching(query, (CFTypeRef *)&items); // If there are not results, that's fine; this class is just empty if (errSecItemNotFound != status) { SRHandleError(status, true); for (int j = 0; j < CFArrayGetCount(items); j++) { CFDictionaryRef properties = CFArrayGetValueAtIndex(items, j); CFMutableDictionaryRef newProperties = CFDictionaryCreateMutableCopy(NULL, 0, properties); CFDictionarySetValue(newProperties, kSRAttrClass, class); CFArrayAppendValue(allItems, newProperties); CFRelease(newProperties); } CFRelease(items); } }
// static bool OTKeyring::IOS_RetrieveSecret(const OTString& strUser, OTPassword& thePassword, const std::string& str_display) { OT_ASSERT(strUser.Exists()); CFStringRef service_name = CFSTR("opentxs"); CFStringRef account_name = CFStringCreateWithCString(nullptr, strUser.Get(), kCFStringEncodingUTF8); CFDataRef vData = nullptr; const void* keys[] = {kSecClass, kSecAttrService, kSecAttrAccount, kSecReturnData}; const void* values[] = {kSecClassGenericPassword, service_name, account_name, kCFBooleanTrue}; CFDictionaryRef query = CFDictionaryCreate(nullptr, keys, values, 4, nullptr, nullptr); OSStatus theError = SecItemCopyMatching(query, (CFTypeRef*)&vData); CFRelease(query); CFRelease(account_name); if (theError != noErr) { otErr << "OTKeyring::IOS_RetrieveSecret: Error in SecItemCopyMatching.\n"; return false; } thePassword.setMemory(CFDataGetBytePtr(vData), CFDataGetLength(vData)); CFRelease(vData); return true; }
static OSStatus EAPSecIdentityListCreate(CFArrayRef * ret_array) { const void * keys[] = { kSecClass, kSecReturnRef, kSecMatchLimit }; CFDictionaryRef query; CFTypeRef results = NULL; OSStatus status = errSecSuccess; const void * values[] = { kSecClassIdentity, kCFBooleanTrue, kSecMatchLimitAll }; query = CFDictionaryCreate(NULL, keys, values, array_size(keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); ok_status(status = SecItemCopyMatching(query, &results), "SecItemCopyMatching"); CFReleaseNull(query); if (status == errSecSuccess) { *ret_array = results; } return (status); }
CFArrayRef CreateKeychainItems(const std::set<std::string>& paths, const CFTypeRef& item_type) { auto keychains = CFArrayCreateMutable(nullptr, 0, &kCFTypeArrayCallBacks); for (const auto& path : paths) { genKeychains(path, keychains); } CFMutableDictionaryRef query; query = CFDictionaryCreateMutable(nullptr, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionaryAddValue(query, kSecClass, item_type); CFDictionaryAddValue(query, kSecReturnRef, kCFBooleanTrue); // This can be added to restrict results to x509v3 // CFDictionaryAddValue(query, kSecAttrCertificateType, 0x03); CFDictionaryAddValue(query, kSecMatchSearchList, keychains); CFDictionaryAddValue(query, kSecAttrCanVerify, kCFBooleanTrue); CFDictionaryAddValue(query, kSecMatchLimit, kSecMatchLimitAll); CFArrayRef keychain_certs; auto status = SecItemCopyMatching(query, (CFTypeRef*)&keychain_certs); CFRelease(query); if (status != errSecSuccess) { return nullptr; } // Release each keychain search path. CFRelease(keychains); return keychain_certs; }
static void ensureKeychainExists(void) { CFDictionaryRef query = CFDictionaryCreate(0, &kSecClass, &kSecClassInternetPassword, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFTypeRef results = NULL; is_status(SecItemCopyMatching(query, &results), errSecItemNotFound, "expected nothing got %@", results); CFReleaseNull(query); CFReleaseNull(results); }
/******************************************************** *********** SecItemCertificateSource object ************ ********************************************************/ static bool SecItemCertificateSourceCopyParents( SecCertificateSourceRef source, SecCertificateRef certificate, void *context, SecCertificateSourceParents callback) { /* FIXME: Search for things other than just subject of our issuer if we have a subjectID or authorityKeyIdentifier. */ CFDataRef normalizedIssuer = SecCertificateGetNormalizedIssuerContent(certificate); const void *keys[] = { kSecClass, kSecReturnRef, kSecMatchLimit, kSecAttrSubject }, *values[] = { kSecClassCertificate, kCFBooleanTrue, kSecMatchLimitAll, normalizedIssuer }; CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, 4, NULL, NULL); CFTypeRef results = NULL; /* We can make this async or run this on a queue now easily. */ OSStatus status = SecItemCopyMatching(query, &results); CFRelease(query); if (status) { secdebug("trust", "SecItemCopyMatching status: %lu", status); } callback(context, results); CFReleaseSafe(results); return true; }
static bool SecItemCertificateSourceContains(SecCertificateSourceRef source, SecCertificateRef certificate) { /* Lookup a certificate by issuer and serial number. */ CFDataRef normalizedSubject = SecCertificateGetNormalizedSubjectContent(certificate); CFDataRef serialNumber = SecCertificateCopySerialNumber(certificate); const void *keys[] = { kSecClass, kSecReturnRef, kSecMatchLimit, kSecAttrIssuer, kSecAttrSerialNumber }, *values[] = { kSecClassCertificate, kCFBooleanTrue, kSecMatchLimitOne, normalizedSubject, serialNumber }; CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, 5, NULL, NULL); OSStatus status = SecItemCopyMatching(query, NULL); CFRelease(query); CFRelease(serialNumber); if (status) { if (status != errSecItemNotFound) { secdebug("trust", "SecItemCopyMatching returned %d", status); } return false; } return true; }
CFArrayRef CUICertificateCredentialProvider::copyMatchingIdentities(CFDictionaryRef attributes, CFTypeRef targetName, CFErrorRef *error) { CFMutableDictionaryRef query = NULL; CFArrayRef result = NULL; CFStringRef name; query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if (query == NULL) return NULL; if (attributes && (name = (CFStringRef)CFDictionaryGetValue(attributes, kCUIAttrName))) { CFDictionarySetValue(query, kSecMatchSubjectContains, name); } CFDictionarySetValue(query, kSecClass, kSecClassIdentity); CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue); CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll); SecItemCopyMatching(query, (CFTypeRef *)&result); CFRelease(query); return result; }
CFDataRef SecKeyCreatePersistentRefToMatchingPrivateKey(SecKeyRef publicKey, CFErrorRef *error) { CFTypeRef persistentRef = NULL; CFDictionaryRef query = CreatePrivateKeyMatchingQuery(publicKey, true); require_quiet(SecError(SecItemCopyMatching(query, &persistentRef),error , CFSTR("Error finding persistent ref to key from public: %@"), publicKey), fail); fail: CFReleaseNull(query); return (CFDataRef)persistentRef; }
static void persistentRefIs(CFDataRef pref, CFDataRef data) { CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); CFTypeRef result = NULL; CFDictionaryAddValue(dict, kSecValuePersistentRef, pref); CFDictionaryAddValue(dict, kSecReturnData, kCFBooleanTrue); ok_status(SecItemCopyMatching(dict, &result), "lookup item data by persistent ref"); ok(CFEqual(data, result), "result %@ equals expected data %@", result, data); CFReleaseNull(result); CFReleaseNull(dict); }
SecKeyRef SecKeyCopyMatchingPrivateKey(SecKeyRef publicKey, CFErrorRef *error) { CFTypeRef private_key = NULL; CFDictionaryRef query = CreatePrivateKeyMatchingQuery(publicKey, false); require_quiet(SecError(SecItemCopyMatching(query, &private_key), error, CFSTR("Error finding private key from public: %@"), publicKey), fail); fail: CFReleaseNull(query); return (SecKeyRef)private_key; }
static void test_persistent2(struct test_persistent_s *p) { CFTypeRef results = NULL; CFTypeRef results2 = NULL; ok_status(!SecItemCopyMatching(p->query, &results), "don't find internet password by attributes"); ok(!results, "no results"); ok_status(!SecItemCopyMatching(p->query2, &results2), "don't find internet password by persistent ref anymore"); ok(!results2, "no results"); SKIP:{ ok_status(SecItemCopyMatching(p->query4, &results2), "find non updated internet password by persistent ref"); skip("non updated internet password by persistent ref NOT FOUND!", 2, results2); ok(results2, "non updated internet password not found"); CFStringRef server = CFDictionaryGetValue(results2, kSecAttrServer); ok(CFEqual(server, CFSTR("zuigt.nl")), "verify second items attribute was not modified by update"); CFReleaseNull(results2); } is_status(SecItemCopyMatching(p->query3, &results2), errSecItemNotFound, "don't find deleted internet password by persistent ref"); CFReleaseNull(results2); ok_status(SecItemCopyMatching(p->query4, &results2), "find non deleted internet password by persistent ref"); CFReleaseNull(results2); ok_status(SecItemDelete(p->query4),"Deleted internet password by persistent ref"); CFRelease(p->query); CFRelease(p->query2); CFRelease(p->query3); CFRelease(p->query4); CFReleaseNull(p->persist[0]); CFReleaseNull(p->persist[1]); }
/* Create an empty keychain file that can't be read or written and make sure securityd can deal with it. */ static void tests(void) { #ifndef NO_SERVER plan_skip_all("No testing against server."); #else const char *home_dir = getenv("HOME"); char keychain_dir[1000]; char keychain_name[1000]; sprintf(keychain_dir, "%s/Library/Keychains", home_dir); sprintf(keychain_name, "%s/keychain-2-debug.db", keychain_dir); ensureKeychainExists(); int fd; ok_unix(fd = open(keychain_name, O_RDWR | O_CREAT | O_TRUNC, 0644), "create keychain file '%s'", keychain_name); ok_unix(fchmod(fd, 0), " keychain file '%s'", keychain_name); ok_unix(close(fd), "close keychain file '%s'", keychain_name); kc_dbhandle_reset(); int v_eighty = 80; CFNumberRef eighty = CFNumberCreate(NULL, kCFNumberSInt32Type, &v_eighty); const char *v_data = "test"; CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data)); CFMutableDictionaryRef query = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); CFDictionaryAddValue(query, kSecClass, kSecClassInternetPassword); CFDictionaryAddValue(query, kSecAttrServer, CFSTR("members.spamcop.net")); CFDictionaryAddValue(query, kSecAttrAccount, CFSTR("smith")); CFDictionaryAddValue(query, kSecAttrPort, eighty); CFDictionaryAddValue(query, kSecAttrProtocol, kSecAttrProtocolHTTP); CFDictionaryAddValue(query, kSecAttrAuthenticationType, kSecAttrAuthenticationTypeDefault); CFDictionaryAddValue(query, kSecValueData, pwdata); ok_status(SecItemAdd(query, NULL), "add internet password"); is_status(SecItemAdd(query, NULL), errSecDuplicateItem, "add internet password again"); ok_status(SecItemCopyMatching(query, NULL), "Found the item we added"); ok_status(SecItemDelete(query),"Deleted the item we added"); CFReleaseSafe(eighty); CFReleaseSafe(pwdata); CFReleaseSafe(query); #endif }
/** * Searches certificates in all opened system keychains. Takes an optional * \p query that defines filter attributes to be searched for. That query * is amended by generic attributes for "certificate filtering". * * \param query a list of key-value pairs used for filtering * \returns an array with the resulting certificates or nullptr if * no matching certificate was found */ scoped_CFType<CFArrayRef> search(Query query = Query()) const { scoped_CFType<CFDictionaryRef> fullQuery( prepareQuery(std::move(query))); check_notnull(fullQuery, "create search query"); scoped_CFType<CFArrayRef> result(nullptr); auto status = SecItemCopyMatching(fullQuery.get(), (CFTypeRef*)&result.get()); if(errSecItemNotFound == status) { return scoped_CFType<CFArrayRef>(nullptr); // no matches } check_success(status, "look up certificate"); check_notnull(result, "look up certificate (invalid result value)"); return result; }
static OSStatus do_query(void) { /* querying a password */ const void *keys[] = { kSecClass, kSecAttrServer, kSecReturnAttributes, }; const void *values[] = { kSecClassInternetPassword, CFSTR("corrupt.spamcop.net"), kCFBooleanTrue, }; CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, array_size(keys), NULL, NULL); CFTypeRef results = NULL; OSStatus err = SecItemCopyMatching(query, &results); CFReleaseNull(query); return err; }
std::vector<char> metadata_realm_encryption_key() { const size_t key_size = 64; const std::string service = "io.realm.sync.keychain"; const std::string account = "metadata"; auto search_dictionary = build_search_dictionary(account, service, none); CFDataRef retained_key_data; if (OSStatus status = SecItemCopyMatching(search_dictionary.get(), (CFTypeRef *)&retained_key_data)) { if (status != errSecItemNotFound) { throw KeychainAccessException(status); } // Key was not found. Generate a new key, store it, and return it. std::vector<char> key(key_size); arc4random_buf(key.data(), key_size); auto key_data = adoptCF(CFDataCreate(nullptr, reinterpret_cast<const UInt8 *>(key.data()), key_size)); if (!key_data) { throw std::bad_alloc(); } CFDictionaryAddValue(search_dictionary.get(), kSecValueData, key_data.get()); if (OSStatus status = SecItemAdd(search_dictionary.get(), nullptr)) { throw KeychainAccessException(status); } return key; } CFPtr<CFDataRef> key_data = adoptCF(retained_key_data); // Key was previously stored. Extract it. if (key_size != CFDataGetLength(key_data.get())) { throw std::runtime_error("Password stored in keychain was not expected size."); } auto key_bytes = reinterpret_cast<const char *>(CFDataGetBytePtr(key_data.get())); return std::vector<char>(key_bytes, key_bytes + key_size); }
static VALUE rb_keychain_item_reload(VALUE self){ SecKeychainItemRef keychainItem=NULL; Data_Get_Struct(self, struct OpaqueSecKeychainItemRef, keychainItem); CFMutableDictionaryRef query = sec_query_identifying_item(keychainItem); CFDictionarySetValue(query, kSecReturnAttributes, kCFBooleanTrue); CFStringRef cfclass = rb_copy_item_class(keychainItem); CFDictionarySetValue(query, kSecClass, cfclass); CFRelease(cfclass); CFDictionaryRef attributes; OSStatus result = SecItemCopyMatching(query, (CFTypeRef*)&attributes); CFRelease(query); CheckOSStatusOrRaise(result); VALUE new_attributes = rb_hash_new(); CFDictionaryApplyFunction(attributes, cf_hash_to_rb_hash, (void*)new_attributes); rb_ivar_set(self, rb_intern("@attributes"), new_attributes); rb_ivar_set(self, rb_intern("unsaved_password"), Qnil); CFRelease(attributes); return self; }
CFDataRef SOSItemCopy(CFStringRef service, CFErrorRef* error) { CFDictionaryRef query = SOSItemCopyQueryForSyncItems(service, true); CFDataRef result = NULL; OSStatus copyResult = SecItemCopyMatching(query, (CFTypeRef*) &result); CFReleaseNull(query); if (copyResult != noErr) { SecError(copyResult, error, CFSTR("Error %@ reading for service '%@'"), result, service); CFReleaseNull(result); return NULL; } if (!isData(result)) { SOSCreateErrorWithFormat(kSOSErrorProcessingFailure, NULL, error, NULL, CFSTR("SecItemCopyMatching returned non-data in '%@'"), service); CFReleaseNull(result); return NULL; } return result; }
static VALUE rb_keychain_find(int argc, VALUE *argv, VALUE self){ VALUE kind; VALUE attributes; VALUE first_or_all; rb_scan_args(argc, argv, "2:", &first_or_all, &kind, &attributes); Check_Type(first_or_all, T_SYMBOL); Check_Type(kind, T_STRING); CFMutableDictionaryRef query = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionarySetValue(query, kSecReturnAttributes, kCFBooleanTrue); CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue); if(rb_to_id(first_or_all) == rb_intern("all")){ CFDictionarySetValue(query, kSecMatchLimit, kSecMatchLimitAll); } rb_add_value_to_cf_dictionary(query, kSecClass, kind); if(!NIL_P(attributes)){ Check_Type(attributes, T_HASH); VALUE rb_keychains = rb_hash_aref(attributes, ID2SYM(rb_intern("keychains"))); if(!NIL_P(rb_keychains)){ Check_Type(rb_keychains, T_ARRAY); CFMutableArrayRef searchArray = CFArrayCreateMutable(NULL, RARRAY_LEN(rb_keychains), &kCFTypeArrayCallBacks); for(int index=0; index < RARRAY_LEN(rb_keychains); index++){ SecKeychainRef keychain = NULL; Data_Get_Struct(RARRAY_PTR(rb_keychains)[index], struct OpaqueSecKeychainRef, keychain); CFArrayAppendValue(searchArray, keychain); } CFDictionarySetValue(query, kSecMatchSearchList,searchArray); CFRelease(searchArray); } VALUE limit = rb_hash_aref(attributes, ID2SYM(rb_intern("limit"))); if(!NIL_P(limit)){ Check_Type(limit, T_FIXNUM); long c_limit = FIX2LONG(limit); CFNumberRef cf_limit = CFNumberCreate(NULL, kCFNumberLongType, &c_limit); CFDictionarySetValue(query, kSecMatchLimit, cf_limit); CFRelease(cf_limit); } VALUE conditions = rb_hash_aref(attributes, ID2SYM(rb_intern("conditions"))); if(!NIL_P(conditions)){ Check_Type(conditions, T_HASH); VALUE rQuery = Data_Wrap_Struct(rb_cPointerWrapper, NULL, NULL, query); rb_block_call(conditions, rb_intern("each"), 0, NULL, RUBY_METHOD_FUNC(add_conditions_to_query), rQuery); } } CFDictionaryRef result; OSStatus status = SecItemCopyMatching(query, (CFTypeRef*)&result); CFRelease(query); VALUE rb_item = rb_ary_new2(0); switch(status){ case errSecItemNotFound: break; default: CheckOSStatusOrRaise(status); if(CFArrayGetTypeID() == CFGetTypeID(result)){ CFArrayRef result_array = (CFArrayRef)result; for(CFIndex i = 0; i < CFArrayGetCount(result_array); i++){ rb_ary_push(rb_item,rb_keychain_item_from_sec_dictionary(CFArrayGetValueAtIndex(result_array,i))); } } else{ rb_ary_push(rb_item, rb_keychain_item_from_sec_dictionary(result)); } CFRelease(result); } if(rb_to_id(first_or_all) == rb_intern("first")){ return rb_ary_entry(rb_item,0); } else{ return rb_item; } }
static CFArrayRef /* O - Array of certificates */ copy_cdsa_certificate( cupsd_client_t *con) /* I - Client connection */ { OSStatus err; /* Error info */ SecKeychainRef keychain = NULL;/* Keychain reference */ SecIdentitySearchRef search = NULL; /* Search reference */ SecIdentityRef identity = NULL;/* Identity */ CFArrayRef certificates = NULL; /* Certificate array */ SecPolicyRef policy = NULL; /* Policy ref */ CFStringRef servername = NULL; /* Server name */ CFMutableDictionaryRef query = NULL; /* Query qualifiers */ CFArrayRef list = NULL; /* Keychain list */ # if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) char localname[1024];/* Local hostname */ # endif /* HAVE_DNSSD || HAVE_AVAHI */ cupsdLogMessage(CUPSD_LOG_DEBUG, "copy_cdsa_certificate: Looking for certs for \"%s\".", con->servername); if ((err = SecKeychainOpen(ServerCertificate, &keychain))) { cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot open keychain \"%s\" - %s (%d)", ServerCertificate, cssmErrorString(err), (int)err); goto cleanup; } servername = CFStringCreateWithCString(kCFAllocatorDefault, con->servername, kCFStringEncodingUTF8); policy = SecPolicyCreateSSL(1, servername); if (servername) CFRelease(servername); if (!policy) { cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create ssl policy reference"); goto cleanup; } if (!(query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks))) { cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create query dictionary"); goto cleanup; } list = CFArrayCreate(kCFAllocatorDefault, (const void **)&keychain, 1, &kCFTypeArrayCallBacks); CFDictionaryAddValue(query, kSecClass, kSecClassIdentity); CFDictionaryAddValue(query, kSecMatchPolicy, policy); CFDictionaryAddValue(query, kSecReturnRef, kCFBooleanTrue); CFDictionaryAddValue(query, kSecMatchLimit, kSecMatchLimitOne); CFDictionaryAddValue(query, kSecMatchSearchList, list); CFRelease(list); err = SecItemCopyMatching(query, (CFTypeRef *)&identity); # if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) if (err && DNSSDHostName) { /* * Search for the connection server name failed; try the DNS-SD .local * hostname instead... */ snprintf(localname, sizeof(localname), "%s.local", DNSSDHostName); cupsdLogMessage(CUPSD_LOG_DEBUG, "copy_cdsa_certificate: Looking for certs for \"%s\".", localname); servername = CFStringCreateWithCString(kCFAllocatorDefault, localname, kCFStringEncodingUTF8); CFRelease(policy); policy = SecPolicyCreateSSL(1, servername); if (servername) CFRelease(servername); if (!policy) { cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create ssl policy reference"); goto cleanup; } CFDictionarySetValue(query, kSecMatchPolicy, policy); err = SecItemCopyMatching(query, (CFTypeRef *)&identity); } # endif /* HAVE_DNSSD || HAVE_AVAHI */ if (err) { cupsdLogMessage(CUPSD_LOG_DEBUG, "Cannot find signing key in keychain \"%s\": %s (%d)", ServerCertificate, cssmErrorString(err), (int)err); goto cleanup; } if (CFGetTypeID(identity) != SecIdentityGetTypeID()) { cupsdLogMessage(CUPSD_LOG_ERROR, "SecIdentity CFTypeID failure."); goto cleanup; } if ((certificates = CFArrayCreate(NULL, (const void **)&identity, 1, &kCFTypeArrayCallBacks)) == NULL) { cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot create certificate array"); goto cleanup; } cleanup : if (keychain) CFRelease(keychain); if (search) CFRelease(search); if (identity) CFRelease(identity); if (policy) CFRelease(policy); if (query) CFRelease(query); return (certificates); }
static value cert_load_defaults(){ #if defined(NEKO_WINDOWS) value v; HCERTSTORE store; PCCERT_CONTEXT cert; mbedtls_x509_crt *chain = (mbedtls_x509_crt *)alloc(sizeof(mbedtls_x509_crt)); mbedtls_x509_crt_init( chain ); if( store = CertOpenSystemStore(0, (LPCSTR)"Root") ){ cert = NULL; while( cert = CertEnumCertificatesInStore(store, cert) ) mbedtls_x509_crt_parse_der( chain, (unsigned char *)cert->pbCertEncoded, cert->cbCertEncoded ); CertCloseStore(store, 0); } v = alloc_abstract(k_cert, chain); val_gc(v,free_cert); return v; #elif defined(NEKO_MAC) CFMutableDictionaryRef search; CFArrayRef result; SecKeychainRef keychain; SecCertificateRef item; CFDataRef dat; value v; mbedtls_x509_crt *chain = NULL; // Load keychain if( SecKeychainOpen("/System/Library/Keychains/SystemRootCertificates.keychain",&keychain) != errSecSuccess ) return val_null; // Search for certificates search = CFDictionaryCreateMutable( NULL, 0, NULL, NULL ); CFDictionarySetValue( search, kSecClass, kSecClassCertificate ); CFDictionarySetValue( search, kSecMatchLimit, kSecMatchLimitAll ); CFDictionarySetValue( search, kSecReturnRef, kCFBooleanTrue ); CFDictionarySetValue( search, kSecMatchSearchList, CFArrayCreate(NULL, (const void **)&keychain, 1, NULL) ); if( SecItemCopyMatching( search, (CFTypeRef *)&result ) == errSecSuccess ){ CFIndex n = CFArrayGetCount( result ); for( CFIndex i = 0; i < n; i++ ){ item = (SecCertificateRef)CFArrayGetValueAtIndex( result, i ); // Get certificate in DER format dat = SecCertificateCopyData( item ); if( dat ){ if( chain == NULL ){ chain = (mbedtls_x509_crt *)alloc(sizeof(mbedtls_x509_crt)); mbedtls_x509_crt_init( chain ); } mbedtls_x509_crt_parse_der( chain, (unsigned char *)CFDataGetBytePtr(dat), CFDataGetLength(dat) ); CFRelease( dat ); } } } CFRelease(keychain); if( chain != NULL ){ v = alloc_abstract(k_cert, chain); val_gc(v,free_cert); return v; }else{ return val_null; } #else return val_null; #endif }
/* Test low level keychain migration from device to device interface. */ static void tests(void) { int v_eighty = 80; CFNumberRef eighty = CFNumberCreate(NULL, kCFNumberSInt32Type, &v_eighty); const char *v_data = "test"; CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data)); CFMutableDictionaryRef query = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); CFDictionaryAddValue(query, kSecClass, kSecClassInternetPassword); CFDictionaryAddValue(query, kSecAttrServer, CFSTR("members.spamcop.net")); CFDictionaryAddValue(query, kSecAttrAccount, CFSTR("smith")); CFDictionaryAddValue(query, kSecAttrPort, eighty); CFDictionaryAddValue(query, kSecAttrProtocol, kSecAttrProtocolHTTP); CFDictionaryAddValue(query, kSecAttrAuthenticationType, kSecAttrAuthenticationTypeDefault); CFDictionaryAddValue(query, kSecValueData, pwdata); // NUKE anything we might have left around from a previous test run so we don't crash. SecItemDelete(query); ok_status(SecItemAdd(query, NULL), "add internet password"); is_status(SecItemAdd(query, NULL), errSecDuplicateItem, "add internet password again"); ok_status(SecItemCopyMatching(query, NULL), "Found the item we added"); struct test_persistent_s p = {}; test_persistent(&p); CFDataRef backup = NULL, keybag = NULL, password = NULL; test_add_lockdown_identity_items(); #if USE_KEYSTORE keybag = create_keybag(kAppleKeyStoreBackupBag, password); #else keybag = CFDataCreate(kCFAllocatorDefault, NULL, 0); #endif ok(backup = _SecKeychainCopyBackup(keybag, password), "_SecKeychainCopyBackup"); test_add_managedconfiguration_item(); test_remove_lockdown_identity_items(); ok_status(_SecKeychainRestoreBackup(backup, keybag, password), "_SecKeychainRestoreBackup"); CFReleaseSafe(backup); test_no_find_lockdown_identity_item(); test_find_managedconfiguration_item(); ok_status(SecItemCopyMatching(query, NULL), "Found the item we added after restore"); test_persistent2(&p); #if USE_KEYSTORE CFReleaseNull(keybag); keybag = create_keybag(kAppleKeyStoreOTABackupBag, password); #endif ok(backup = _SecKeychainCopyBackup(keybag, password), "_SecKeychainCopyBackup"); ok_status(_SecKeychainRestoreBackup(backup, keybag, password), "_SecKeychainRestoreBackup"); ok_status(SecItemCopyMatching(query, NULL), "Found the item we added after restore"); CFReleaseNull(backup); // force tombstone to be added, since it's not the default behavior per rdar://14680869 CFDictionaryAddValue(query, kSecUseTombstones, kCFBooleanTrue); ok_status(SecItemDelete(query), "Deleted item we added"); #if USE_KEYSTORE CFReleaseNull(keybag); keybag = create_keybag(kAppleKeyStoreOTABackupBag /* use truthiness bag once it's there */, password); #endif // add syncable item CFDictionaryAddValue(query, kSecAttrSynchronizable, kCFBooleanTrue); ok_status(SecItemAdd(query, NULL), "add internet password"); // and non-syncable item test_add_managedconfiguration_item(); CFDictionaryRef syncableBackup = NULL; CFErrorRef error = NULL; CFDictionaryRef scratch = NULL; SKIP: { skip("skipping syncable backup tests", 7, ok_status(_SecKeychainBackupSyncable(keybag, password, NULL, &syncableBackup), "export items")); // TODO: add item, call SecServerCopyTruthInTheCloud again // CFShow(syncableBackup); // find and delete skip("skipping syncable backup tests", 6, ok_status(SecItemCopyMatching(query, NULL), "find item we are about to destroy")); skip("skipping syncable backup tests", 5, ok_status(SecItemDelete(query), "delete item we backed up")); // ensure we added a tombstone CFDictionaryAddValue(query, kSecAttrTombstone, kCFBooleanTrue); skip("skipping syncable backup tests", 4, ok_status(SecItemCopyMatching(query, NULL), "find tombstone for item we deleted")); CFDictionaryRemoveValue(query, kSecAttrTombstone); test_find_managedconfiguration_item(); // <- 2 tests here // TODO: add a different new item - delete what's not in the syncableBackup? // Do another backup after some changes skip("skipping syncable backup tests", 1, ok_status(_SecKeychainBackupSyncable(keybag, password, syncableBackup, &scratch), "export items after changes")); skip("skipping syncable backup tests", 0, ok_status(_SecKeychainRestoreSyncable(keybag, password, syncableBackup), "import items")); } CFReleaseNull(scratch); CFReleaseNull(error); // non-syncable item should (still) be gone -> add should work test_add_managedconfiguration_item(); test_find_managedconfiguration_item(); // syncable item should have not been restored, because the tombstone was newer than the item in the backup -> copy matching should fail is_status(errSecItemNotFound, SecItemCopyMatching(query, NULL), "find restored item"); is_status(errSecItemNotFound, SecItemDelete(query), "delete restored item"); CFReleaseSafe(syncableBackup); CFReleaseSafe(keybag); CFReleaseSafe(eighty); CFReleaseSafe(pwdata); CFReleaseSafe(query); }
static void test_persistent(struct test_persistent_s *p) { int v_eighty = 80; CFNumberRef eighty = CFNumberCreate(NULL, kCFNumberSInt32Type, &v_eighty); const char *v_data = "test"; CFDataRef pwdata = CFDataCreate(NULL, (UInt8 *)v_data, strlen(v_data)); const void *keys[] = { kSecClass, kSecAttrServer, kSecAttrAccount, kSecAttrPort, kSecAttrProtocol, kSecAttrAuthenticationType, kSecReturnPersistentRef, kSecValueData }; const void *values[] = { kSecClassInternetPassword, CFSTR("zuigt.nl"), CFSTR("frtnbf"), eighty, CFSTR("http"), CFSTR("dflt"), kCFBooleanTrue, pwdata }; CFDictionaryRef item = CFDictionaryCreate(NULL, keys, values, array_size(keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); p->persist[0] = NULL; // NUKE anything we might have left around from a previous test run so we don't crash. SecItemDelete(item); ok_status(SecItemAdd(item, &p->persist[0]), "add internet password"); CFTypeRef results = NULL; CFTypeRef results2 = NULL; SKIP: { skip("no persistent ref", 6, ok(p->persist[0], "got back persistent ref")); /* Create a dict with all attrs except the data. */ keys[(array_size(keys)) - 2] = kSecReturnAttributes; p->query = CFDictionaryCreate(NULL, keys, values, (array_size(keys)) - 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); ok_status(SecItemCopyMatching(p->query, &results), "find internet password by attr"); const void *keys_persist[] = { kSecReturnAttributes, kSecValuePersistentRef }; const void *values_persist[] = { kCFBooleanTrue, p->persist[0] }; p->query2 = CFDictionaryCreate(NULL, keys_persist, values_persist, (array_size(keys_persist)), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); ok_status(SecItemCopyMatching(p->query2, &results2), "find internet password by persistent ref"); ok(CFEqual(results, results2 ? results2 : CFSTR("")), "same item (attributes)"); CFReleaseNull(results); CFReleaseNull(results2); ok_status(SecItemDelete(p->query), "delete internet password"); ok_status(!SecItemCopyMatching(p->query, &results), "don't find internet password by attributes"); ok(!results, "no results"); } /* clean up left over from aborted run */ if (results) { CFDictionaryRef cleanup = CFDictionaryCreate(NULL, &kSecValuePersistentRef, &results, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); SecItemDelete(cleanup); CFRelease(results); CFRelease(cleanup); } ok_status(!SecItemCopyMatching(p->query2, &results2), "don't find internet password by persistent ref anymore"); ok(!results2, "no results"); CFReleaseNull(p->persist[0]); /* Add a new item and get it's persitant ref. */ ok_status(SecItemAdd(item, &p->persist[0]), "add internet password"); p->persist[1] = NULL; CFMutableDictionaryRef item2 = CFDictionaryCreateMutableCopy(NULL, 0, item); CFDictionarySetValue(item2, kSecAttrAccount, CFSTR("johndoe-bu")); // NUKE anything we might have left around from a previous test run so we don't crash. SecItemDelete(item2); ok_status(SecItemAdd(item2, &p->persist[1]), "add second internet password"); CFMutableDictionaryRef update = NULL; CFStringRef server = NULL; SKIP: { skip("no persistent ref", 3, ok(p->persist[0], "got back persistent ref from first internet password")); is(CFGetTypeID(p->persist[0]), CFDataGetTypeID(), "result is a CFData"); p->query3 = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionaryAddValue(p->query3, kSecValuePersistentRef, p->persist[0]); update = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); CFDictionaryAddValue(update, kSecAttrServer, CFSTR("zuigt.com")); ok_status(SecItemUpdate(p->query3, update), "update via persitant ref"); /* Verify that the update really worked. */ CFDictionaryAddValue(p->query3, kSecReturnAttributes, kCFBooleanTrue); ok_status(SecItemCopyMatching(p->query3, &results2), "find updated internet password by persistent ref"); server = CFDictionaryGetValue(results2, kSecAttrServer); ok(CFEqual(server, CFSTR("zuigt.com")), "verify attribute was modified by update"); CFReleaseNull(results2); CFDictionaryRemoveValue(p->query3, kSecReturnAttributes); } SKIP: { skip("no persistent ref", 2, ok(p->persist[1], "got back persistent ref")); /* Verify that item2 wasn't affected by the update. */ p->query4 = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionaryAddValue(p->query4, kSecValuePersistentRef, p->persist[1]); CFDictionaryAddValue(p->query4, kSecReturnAttributes, kCFBooleanTrue); ok_status(SecItemCopyMatching(p->query4, &results2), "find non updated internet password by persistent ref"); server = CFDictionaryGetValue(results2, kSecAttrServer); ok(CFEqual(server, CFSTR("zuigt.nl")), "verify second items attribute was not modified by update"); CFReleaseNull(results2); } /* Delete the item via persitant ref. */ ok_status(SecItemDelete(p->query3), "delete via persitant ref"); is_status(SecItemCopyMatching(p->query3, &results2), errSecItemNotFound, "don't find deleted internet password by persistent ref"); CFReleaseNull(results2); ok_status(SecItemCopyMatching(p->query4, &results2), "find non deleted internet password by persistent ref"); CFReleaseNull(results2); CFReleaseNull(update); CFReleaseNull(item); CFReleaseNull(item2); CFReleaseNull(eighty); CFReleaseNull(pwdata); }
/* Create and identity and try to retrieve it. */ static void tests(void) { SecCertificateRef cert = NULL; SecKeyRef privKey = NULL; SecIdentityRef identity = NULL; isnt(cert = SecCertificateCreateWithBytes(NULL, _c1, sizeof(_c1)), NULL, "create certificate"); isnt(privKey = SecKeyCreateRSAPrivateKey(NULL, _k1, sizeof(_k1), kSecKeyEncodingPkcs1), NULL, "create private key"); const void *certkeys[] = { kSecValueRef }; const void *certvalues[] = { cert }; CFDictionaryRef certDict = CFDictionaryCreate(NULL, certkeys, certvalues, array_size(certkeys), NULL, NULL); ok_status(SecItemAdd(certDict, NULL), "add certificate"); CFReleaseNull(certDict); const void *privkeys[] = { kSecValueRef }; const void *privvalues[] = { privKey }; CFDictionaryRef privDict = CFDictionaryCreate(NULL, privkeys, privvalues, array_size(privkeys), NULL, NULL); ok_status(SecItemAdd(privDict, NULL), "add private key"); CFReleaseNull(privDict); isnt(identity = SecIdentityCreate(NULL, cert, privKey), NULL, "create identity"); /* Lookup the key and certificate using SecItemCopyMatching(). */ CFDataRef pk_digest = CFDataCreate(NULL, _k1_digest, sizeof(_k1_digest)); const void *q_keys[] = { kSecClass, kSecAttrApplicationLabel, kSecReturnRef }; const void *q_values[] = { kSecClassKey, pk_digest, kCFBooleanTrue }; CFDictionaryRef query = CFDictionaryCreate(NULL, q_keys, q_values, array_size(q_keys), NULL, NULL); CFTypeRef result_key; ok_status(SecItemCopyMatching(query, &result_key), "lookup key"); isnt(CFEqual(privKey, result_key), 0, "keys match"); CFReleaseNull(query); q_keys[1] = kSecAttrPublicKeyHash; q_values[0] = kSecClassCertificate; query = CFDictionaryCreate(NULL, q_keys, q_values, array_size(q_keys), NULL, NULL); CFTypeRef result_cert; ok_status(SecItemCopyMatching(query, &result_cert), "lookup certificate"); isnt(CFEqual(cert, result_cert), 0, "certificates match"); CFReleaseNull(query); /* Cleanup. */ CFReleaseNull(result_key); CFReleaseNull(result_cert); /* identity lookup */ const void *idnt_keys[] = { kSecClass, kSecAttrApplicationLabel, kSecReturnRef }; const void *idnt_values[] = { kSecClassIdentity, pk_digest, kCFBooleanTrue }; CFTypeRef result_idnt; SecCertificateRef result_cert2; query = CFDictionaryCreate(NULL, idnt_keys, idnt_values, array_size(idnt_keys), NULL, NULL); ok_status(SecItemCopyMatching(query, &result_idnt), "lookup identity"); isnt(result_idnt, NULL, "found identity?"); is(CFGetRetainCount(result_idnt), 1, "result_idnt rc = 1"); isnt(CFEqual(identity, result_idnt), 0, "identities match"); CFReleaseNull(identity); ok_status(SecIdentityCopyCertificate((SecIdentityRef)result_idnt, &result_cert2), "get cert from identity"); isnt(CFEqual(cert, result_cert2), 0, "certificates match"); CFRelease(query); CFRelease(pk_digest); CFReleaseNull(result_cert2); certDict = CFDictionaryCreate(NULL, certkeys, certvalues, array_size(certkeys), NULL, NULL); ok_status(SecItemDelete(certDict), "delete certificate via ref"); is_status(errSecItemNotFound, SecItemCopyMatching(certDict, NULL), "verify certificate is gone"); CFReleaseNull(certDict); privDict = CFDictionaryCreate(NULL, privkeys, privvalues, array_size(privkeys), NULL, NULL); ok_status(SecItemDelete(privDict), "delete key via ref"); is_status(errSecItemNotFound, SecItemCopyMatching(privDict, NULL), "verify key is gone"); CFReleaseNull(privDict); /* add certificate to offset cert row id from key row id */ SecCertificateRef apple_ca_cert = NULL; isnt(apple_ca_cert = SecCertificateCreateWithBytes(NULL, _c0, sizeof(_c0)), NULL, "create apple ca certificate"); CFDictionaryRef appleCertDict = CFDictionaryCreate(NULL, (const void **)&kSecValueRef, (const void **)&apple_ca_cert, 1, NULL, NULL); ok_status(SecItemAdd(appleCertDict, NULL), "add apple ca certificate to offset key and cert rowid"); /* add identity, get persistent ref */ const void *keys_identity[] = { kSecValueRef, kSecReturnPersistentRef }; const void *values_identity[] = { result_idnt, kCFBooleanTrue }; CFDictionaryRef identity_add = CFDictionaryCreate(NULL, keys_identity, values_identity, array_size(keys_identity), NULL, NULL); CFTypeRef persist = NULL; ok_status(SecItemAdd(identity_add, &persist), "add identity ref"); ok(persist, "got back persistent ref"); /* <rdar://problem/6537195> SecItemAdd returns success when it shouldn't */ CFTypeRef persist_again = NULL; is_status(errSecDuplicateItem, SecItemAdd(identity_add, &persist_again), "fail to add identity ref again"); ok(!persist_again, "no persistent ref this time"); /* find by persistent ref */ const void *keys_persist[] = { kSecReturnRef, kSecValuePersistentRef }; const void *values_persist[] = { kCFBooleanTrue, persist }; CFDictionaryRef persist_find = CFDictionaryCreate(NULL, keys_persist, values_persist, (array_size(keys_persist)), NULL, NULL); CFTypeRef results2 = NULL; ok_status(SecItemCopyMatching(persist_find, &results2), "find identity by persistent ref"); is(CFGetRetainCount(results2), 1, "results2 rc = 1"); // not implemented ok(CFEqual(result_idnt, results2), "same item (attributes)"); CFReleaseNull(results2); /* find identity, key and cert by ref and return persistent ref */ const void *keys_ref_to_persist[] = { kSecReturnPersistentRef, kSecValueRef }; const void *values_ref_to_persist[] = { kCFBooleanTrue, NULL }; CFTypeRef items[] = { result_idnt, privKey, cert, NULL }; CFTypeRef *item = items; while (*item) { values_ref_to_persist[1] = *item; CFDictionaryRef ref_to_persist_find = CFDictionaryCreate(NULL, keys_ref_to_persist, values_ref_to_persist, (array_size(keys_ref_to_persist)), NULL, NULL); results2 = NULL; ok_status(SecItemCopyMatching(ref_to_persist_find, &results2), "find persistent ref for identity ref"); ok(NULL != results2, "good persistent ref"); is(CFGetRetainCount(results2), 1, "results2 rc = 1"); CFReleaseNull(results2); CFReleaseNull(ref_to_persist_find); item++; } /* delete identity by identity ref */ ok_status(SecItemDelete(identity_add), "delete identity by identity ref"); is(SecItemCopyMatching(persist_find, &results2), errSecItemNotFound, "make sure identity by persistent ref is no longer there"); CFRelease(persist_find); CFReleaseNull(persist); ok_status(SecItemAdd(identity_add, &persist), "add identity ref back"); CFRelease(identity_add); /* delete identity by persistent ref */ CFDictionaryRef persist_delete = CFDictionaryCreate(NULL, &kSecValuePersistentRef, &persist, 1, NULL, NULL); ok_status(SecItemDelete(persist_delete), "delete identity by persistent ref"); is(SecItemCopyMatching(persist_delete, &results2), errSecItemNotFound, "make sure identity by persistent ref is no longer there"); CFRelease(persist_delete); CFReleaseNull(persist); /* add identity with a label set */ CFStringRef zomg_label = CFSTR("zomg"); CFMutableDictionaryRef lbl_idnt_query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionarySetValue(lbl_idnt_query, kSecValueRef, result_idnt); CFDictionarySetValue(lbl_idnt_query, kSecAttrLabel, zomg_label); ok_status(SecItemAdd(lbl_idnt_query, NULL), "add identity ref"); /* find identity with label*/ CFDictionaryRemoveAllValues(lbl_idnt_query); CFDictionarySetValue(lbl_idnt_query, kSecClass, kSecClassIdentity); CFDictionarySetValue(lbl_idnt_query, kSecAttrLabel, zomg_label); ok_status(SecItemCopyMatching(lbl_idnt_query, NULL), "find identity by label"); /* find certs with label */ CFTypeRef zomg_cert; CFDictionaryRemoveAllValues(lbl_idnt_query); CFDictionarySetValue(lbl_idnt_query, kSecClass, kSecClassCertificate); CFDictionarySetValue(lbl_idnt_query, kSecAttrLabel, zomg_label); CFDictionarySetValue(lbl_idnt_query, kSecReturnRef, kCFBooleanTrue); ok_status(SecItemCopyMatching(lbl_idnt_query, &zomg_cert), "find cert by label"); /* find keys with label */ CFTypeRef zomg_key; CFDictionaryRemoveAllValues(lbl_idnt_query); CFDictionarySetValue(lbl_idnt_query, kSecClass, kSecClassKey); CFDictionarySetValue(lbl_idnt_query, kSecAttrLabel, zomg_label); CFDictionarySetValue(lbl_idnt_query, kSecReturnRef, kCFBooleanTrue); ok_status(SecItemCopyMatching(lbl_idnt_query, &zomg_key), "find key by label"); /* update label on key */ CFStringRef new_label_value = CFSTR("zzzomg"); CFDictionaryRef new_label = CFDictionaryCreate(kCFAllocatorDefault, (const void **)&kSecAttrLabel, (const void **)&new_label_value, 1, NULL, NULL); CFDictionaryRemoveAllValues(lbl_idnt_query); CFDictionarySetValue(lbl_idnt_query, kSecValueRef, zomg_key); ok_status(SecItemUpdate(lbl_idnt_query, new_label), "update label to zzzomg for key"); CFTypeRef zomg_idnt = NULL; CFDictionaryRemoveAllValues(lbl_idnt_query); CFDictionarySetValue(lbl_idnt_query, kSecReturnRef, kCFBooleanTrue); CFDictionarySetValue(lbl_idnt_query, kSecAttrLabel, zomg_label); CFDictionarySetValue(lbl_idnt_query, kSecClass, kSecClassIdentity); ok_status(SecItemCopyMatching(lbl_idnt_query, &zomg_idnt), "still finding zomg ident"); CFReleaseNull(zomg_idnt); CFDictionaryRemoveAllValues(lbl_idnt_query); CFDictionarySetValue(lbl_idnt_query, kSecValueRef, zomg_cert); ok_status(SecItemUpdate(lbl_idnt_query, new_label), "update label to zzzomg for cert"); CFReleaseNull(new_label); CFDictionaryRemoveAllValues(lbl_idnt_query); CFDictionarySetValue(lbl_idnt_query, kSecReturnRef, kCFBooleanTrue); CFDictionarySetValue(lbl_idnt_query, kSecAttrLabel, zomg_label); CFDictionarySetValue(lbl_idnt_query, kSecClass, kSecClassIdentity); is_status(errSecItemNotFound, SecItemCopyMatching(lbl_idnt_query, &zomg_idnt), "no longer find identity by label"); CFDictionaryRemoveAllValues(lbl_idnt_query); CFDictionarySetValue(lbl_idnt_query, kSecReturnRef, kCFBooleanTrue); CFDictionarySetValue(lbl_idnt_query, kSecAttrLabel, new_label_value); CFDictionarySetValue(lbl_idnt_query, kSecClass, kSecClassIdentity); ok_status(SecItemCopyMatching(lbl_idnt_query, &zomg_idnt), "finding ident with zzzomg label"); /* Find zomg identity with canonical issuer */ { unsigned char DN[] = { 0x30, 0x32, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x07, 0x70, 0x6c, 0x75, 0x74, 0x6f, 0x43, 0x41, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x0c, 0x0f, 0x70, 0x6c, 0x75, 0x74, 0x6f, 0x40, 0x70, 0x6c, 0x75, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d }; unsigned int DN_len = 52; CFMutableDictionaryRef find_by_issuer = CFDictionaryCreateMutable(NULL, 0, NULL, NULL); CFDataRef issuer = SecCertificateGetNormalizedIssuerContent(cert); CFTypeRef found_by_issuer = NULL; CFDictionarySetValue(find_by_issuer, kSecAttrIssuer, issuer); CFDictionarySetValue(find_by_issuer, kSecClass, kSecClassIdentity); CFDictionarySetValue(find_by_issuer, kSecReturnRef, kCFBooleanTrue); ok_status(SecItemCopyMatching(find_by_issuer, &found_by_issuer), "find identity by cert issuer"); ok(CFEqual(found_by_issuer, zomg_idnt), "should be same as zomg_idnt"); CFReleaseNull(found_by_issuer); issuer = CFDataCreate(kCFAllocatorDefault, DN, DN_len); CFDictionarySetValue(find_by_issuer, kSecAttrIssuer, issuer); ok_status(SecItemCopyMatching(find_by_issuer, &found_by_issuer), "find identity by cert issuer"); CFReleaseNull(issuer); ok(CFEqual(found_by_issuer, zomg_idnt), "should be same as zomg_idnt"); CFReleaseNull(found_by_issuer); CFReleaseNull(find_by_issuer); } ok_status(SecItemDelete(lbl_idnt_query), "delete ident with zzzomg label"); /* Delete the apple cert last */ ok_status(SecItemDelete(appleCertDict), "delete apple ca certificate"); CFReleaseNull(appleCertDict); CFReleaseNull(apple_ca_cert); CFRelease(zomg_key); CFRelease(zomg_cert); CFRelease(zomg_idnt); CFRelease(zomg_label); CFRelease(new_label_value); CFRelease(lbl_idnt_query); CFReleaseNull(result_idnt); CFReleaseNull(privKey); CFReleaseNull(cert); }
static void test_find_managedconfiguration_item(void) { CFMutableDictionaryRef query = test_create_managedconfiguration_query(); ok_status(SecItemCopyMatching(query, NULL), "test_find_managedconfiguration_item"); ok_status(SecItemDelete(query), "test_find_managedconfiguration_item (deleted)"); CFReleaseSafe(query); }
static void testkeygen2(size_t keySizeInBits) { SecKeyRef pubKey = NULL, privKey = NULL; size_t keySizeInBytes = (keySizeInBits + 7) / 8; CFNumberRef kzib; int32_t keysz32 = (int32_t)keySizeInBits; CFUUIDRef ourUUID = CFUUIDCreate(kCFAllocatorDefault); CFStringRef uuidString = CFUUIDCreateString(kCFAllocatorDefault, ourUUID); CFMutableStringRef publicName = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, uuidString); CFMutableStringRef privateName = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, uuidString); CFReleaseNull(ourUUID); CFReleaseNull(uuidString); CFStringAppend(publicName, CFSTR("-Public-41")); CFStringAppend(privateName, CFSTR("-Private-41")); CFMutableDictionaryRef pubd = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, kSecAttrLabel, publicName, NULL); CFMutableDictionaryRef privd = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, kSecAttrLabel, privateName, NULL); kzib = CFNumberCreate(NULL, kCFNumberSInt32Type, &keysz32); CFDictionaryRef kgp = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, kSecAttrKeyType, kSecAttrKeyTypeEC, kSecAttrKeySizeInBits, kzib, kSecAttrIsPermanent, kCFBooleanTrue, kSecPublicKeyAttrs, pubd, kSecPrivateKeyAttrs, privd, NULL); CFReleaseNull(kzib); OSStatus status; ok_status(status = SecKeyGeneratePair(kgp, &pubKey, &privKey), "Generate %ld bit (%ld byte) persistent RSA keypair", keySizeInBits, keySizeInBytes); CFReleaseNull(kgp); SKIP: { skip("keygen failed", 8, status == errSecSuccess); ok(pubKey, "pubkey returned"); ok(privKey, "privKey returned"); is(SecKeyGetSize(pubKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "public key size is ok"); is(SecKeyGetSize(privKey, kSecKeyKeySizeInBits), (size_t) keySizeInBits, "private key size is ok"); SecKeyRef pubKey2, privKey2; CFDictionaryAddValue(pubd, kSecClass, kSecClassKey); CFDictionaryAddValue(pubd, kSecReturnRef, kCFBooleanTrue); CFDictionaryAddValue(privd, kSecClass, kSecClassKey); CFDictionaryAddValue(privd, kSecReturnRef, kCFBooleanTrue); CFDictionaryAddValue(privd, kSecAttrCanSign, kCFBooleanTrue); ok_status(SecItemCopyMatching(pubd, (CFTypeRef *)&pubKey2), "retrieve pub key by label"); ok(pubKey2, "got valid object"); ok_status(SecItemCopyMatching(privd, (CFTypeRef *)&privKey2), "retrieve priv key by label and kSecAttrCanSign"); ok(privKey2, "got valid object"); /* Sign something. */ uint8_t something[20] = {0x80, 0xbe, 0xef, 0xba, 0xd0, }; size_t sigLen = SecKeyGetSize(privKey2, kSecKeySignatureSize); uint8_t sig[sigLen]; ok_status(SecKeyRawSign(privKey2, kSecPaddingPKCS1, something, sizeof(something), sig, &sigLen), "sign something"); ok_status(SecKeyRawVerify(pubKey2, kSecPaddingPKCS1, something, sizeof(something), sig, sigLen), "verify sig on something"); /* Cleanup. */ CFReleaseNull(pubKey2); CFReleaseNull(privKey2); } /* delete from keychain - note: do it before releasing publicName and privateName because pubd and privd have no retain/release callbacks */ ok_status(SecItemDelete(pubd), "delete generated pub key"); ok_status(SecItemDelete(privd), "delete generated priv key"); /* Cleanup. */ CFReleaseNull(pubKey); CFReleaseNull(privKey); CFReleaseNull(publicName); CFReleaseNull(privateName); CFReleaseNull(pubd); CFReleaseNull(privd); }
static int keychain_query(hx509_context context, hx509_certs certs, void *data, const hx509_query *query, hx509_cert *retcert) { CFArrayRef identities = NULL; hx509_cert cert = NULL; CFIndex n, count; int ret; int kdcLookupHack = 0; /* * First to course filtering using security framework .... */ #define FASTER_FLAGS (HX509_QUERY_MATCH_PERSISTENT|HX509_QUERY_PRIVATE_KEY) if ((query->match & FASTER_FLAGS) == 0) return HX509_UNIMPLEMENTED_OPERATION; CFMutableDictionaryRef secQuery = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); /* * XXX this is so broken, SecItem doesn't find the kdc certificte, * and kdc certificates happend to be searched by friendly name, * so find that and mundge on the structure. */ if ((query->match & HX509_QUERY_MATCH_FRIENDLY_NAME) && (query->match & HX509_QUERY_PRIVATE_KEY) && strcmp(query->friendlyname, "O=System Identity,CN=com.apple.kerberos.kdc") == 0) { ((hx509_query *)query)->match &= ~HX509_QUERY_PRIVATE_KEY; kdcLookupHack = 1; } if (kdcLookupHack || (query->match & HX509_QUERY_MATCH_PERSISTENT)) { CFDictionaryAddValue(secQuery, kSecClass, kSecClassCertificate); } else CFDictionaryAddValue(secQuery, kSecClass, kSecClassIdentity); CFDictionaryAddValue(secQuery, kSecReturnRef, kCFBooleanTrue); CFDictionaryAddValue(secQuery, kSecMatchLimit, kSecMatchLimitAll); if (query->match & HX509_QUERY_MATCH_PERSISTENT) { CFDataRef refdata = CFDataCreateWithBytesNoCopy(NULL, query->persistent->data, query->persistent->length, kCFAllocatorNull); CFDictionaryAddValue(secQuery, kSecValuePersistentRef, refdata); CFRelease(refdata); } OSStatus status = SecItemCopyMatching(secQuery, (CFTypeRef *)&identities); CFRelease(secQuery); if (status || identities == NULL) { hx509_clear_error_string(context); return HX509_CERT_NOT_FOUND; } heim_assert(CFArrayGetTypeID() == CFGetTypeID(identities), "return value not an array"); /* * ... now do hx509 filtering */ count = CFArrayGetCount(identities); for (n = 0; n < count; n++) { CFTypeRef secitem = (CFTypeRef)CFArrayGetValueAtIndex(identities, n); #ifndef __APPLE_TARGET_EMBEDDED__ if (query->match & HX509_QUERY_MATCH_PERSISTENT) { SecIdentityRef other = NULL; OSStatus osret; osret = SecIdentityCreateWithCertificate(NULL, (SecCertificateRef)secitem, &other); if (osret == noErr) { ret = hx509_cert_init_SecFramework(context, (void *)other, &cert); CFRelease(other); if (ret) continue; } else { ret = hx509_cert_init_SecFramework(context, (void *)secitem, &cert); if (ret) continue; } } else #endif { ret = hx509_cert_init_SecFramework(context, (void *)secitem, &cert); if (ret) continue; } if (_hx509_query_match_cert(context, query, cert)) { #ifndef __APPLE_TARGET_EMBEDDED__ /* certtool/keychain doesn't glue togheter the cert with keys for system keys */ if (kdcLookupHack) { SecIdentityRef other = NULL; OSStatus osret; osret = SecIdentityCreateWithCertificate(NULL, (SecCertificateRef)secitem, &other); if (osret == noErr) { hx509_cert_free(cert); ret = hx509_cert_init_SecFramework(context, other, &cert); CFRelease(other); if (ret) continue; } } #endif *retcert = cert; break; } hx509_cert_free(cert); } if (kdcLookupHack) ((hx509_query *)query)->match |= HX509_QUERY_PRIVATE_KEY; CFRelease(identities); if (*retcert == NULL) { hx509_clear_error_string(context); return HX509_CERT_NOT_FOUND; } return 0; }
static int keychain_iter_start(hx509_context context, hx509_certs certs, void *data, void **cursor) { #ifndef __APPLE_TARGET_EMBEDDED__ struct ks_keychain *ctx = data; #endif struct iter *iter; iter = calloc(1, sizeof(*iter)); if (iter == NULL) { hx509_set_error_string(context, 0, ENOMEM, "out of memory"); return ENOMEM; } #ifndef __APPLE_TARGET_EMBEDDED__ if (ctx->anchors) { CFArrayRef anchors; int ret; int i; ret = hx509_certs_init(context, "MEMORY:ks-file-create", 0, NULL, &iter->certs); if (ret) { free(iter); return ret; } ret = SecTrustCopyAnchorCertificates(&anchors); if (ret != 0) { hx509_certs_free(&iter->certs); free(iter); hx509_set_error_string(context, 0, ENOMEM, "Can't get trust anchors from Keychain"); return ENOMEM; } for (i = 0; i < CFArrayGetCount(anchors); i++) { SecCertificateRef cr; hx509_cert cert; CFDataRef dataref; cr = (SecCertificateRef)CFArrayGetValueAtIndex(anchors, i); dataref = SecCertificateCopyData(cr); if (dataref == NULL) continue; ret = hx509_cert_init_data(context, CFDataGetBytePtr(dataref), CFDataGetLength(dataref), &cert); CFRelease(dataref); if (ret) continue; ret = hx509_certs_add(context, iter->certs, cert); hx509_cert_free(cert); } CFRelease(anchors); if (ret != 0) { hx509_certs_free(&iter->certs); free(iter); hx509_set_error_string(context, 0, ret, "Failed to add cert"); return ret; } } if (iter->certs) { int ret; ret = hx509_certs_start_seq(context, iter->certs, &iter->cursor); if (ret) { hx509_certs_free(&iter->certs); free(iter); return ret; } } else #endif { OSStatus ret; const void *keys[] = { kSecClass, kSecReturnRef, kSecMatchLimit }; const void *values[] = { kSecClassCertificate, kCFBooleanTrue, kSecMatchLimitAll }; CFDictionaryRef secQuery; secQuery = CFDictionaryCreate(NULL, keys, values, sizeof(keys) / sizeof(*keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); ret = SecItemCopyMatching(secQuery, (CFTypeRef *)&iter->search); CFRelease(secQuery); if (ret) { free(iter); return ENOMEM; } } *cursor = iter; return 0; }
extern "C" int32_t AppleCryptoNative_X509CopyWithPrivateKey(SecCertificateRef cert, SecKeyRef privateKey, SecKeychainRef targetKeychain, SecIdentityRef* pIdentityOut, int32_t* pOSStatus) { if (pIdentityOut != nullptr) *pIdentityOut = nullptr; if (pOSStatus != nullptr) *pOSStatus = noErr; if (cert == nullptr || privateKey == nullptr || targetKeychain == nullptr || pIdentityOut == nullptr || pOSStatus == nullptr) { return -1; } SecKeychainRef keyKeychain = nullptr; OSStatus status = SecKeychainItemCopyKeychain(reinterpret_cast<SecKeychainItemRef>(privateKey), &keyKeychain); SecKeychainItemRef itemCopy = nullptr; // This only happens with an ephemeral key, so the keychain we're adding it to is temporary. if (status == errSecNoSuchKeychain) { status = AddKeyToKeychain(privateKey, targetKeychain); } if (itemCopy != nullptr) { CFRelease(itemCopy); } CFMutableDictionaryRef query = nullptr; if (status == noErr) { query = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if (query == nullptr) { status = errSecAllocate; } } CFArrayRef searchList = nullptr; if (status == noErr) { searchList = CFArrayCreate( nullptr, const_cast<const void**>(reinterpret_cast<void**>(&targetKeychain)), 1, &kCFTypeArrayCallBacks); if (searchList == nullptr) { status = errSecAllocate; } } CFArrayRef itemMatch = nullptr; if (status == noErr) { itemMatch = CFArrayCreate( nullptr, const_cast<const void**>(reinterpret_cast<void**>(&cert)), 1, &kCFTypeArrayCallBacks); if (itemMatch == nullptr) { status = errSecAllocate; } } CFTypeRef result = nullptr; if (status == noErr) { CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue); CFDictionarySetValue(query, kSecMatchSearchList, searchList); CFDictionarySetValue(query, kSecMatchItemList, itemMatch); CFDictionarySetValue(query, kSecClass, kSecClassIdentity); status = SecItemCopyMatching(query, &result); if (status != noErr && result != nullptr) { CFRelease(result); result = nullptr; } bool added = false; if (status == errSecItemNotFound) { status = SecCertificateAddToKeychain(cert, targetKeychain); added = (status == noErr); } if (result == nullptr && status == noErr) { status = SecItemCopyMatching(query, &result); } if (result != nullptr && status == noErr) { if (CFGetTypeID(result) != SecIdentityGetTypeID()) { status = errSecItemNotFound; } else { SecIdentityRef identity = reinterpret_cast<SecIdentityRef>(const_cast<void*>(result)); CFRetain(identity); *pIdentityOut = identity; } } if (added) { // The same query that was used to find the identity can be used // to find/delete the certificate, as long as we fix the class to just the cert. CFDictionarySetValue(query, kSecClass, kSecClassCertificate); // Ignore the output status, there's no point in telling the user // that the cleanup failed, since that just makes them have a dirty keychain // AND their program didn't work. SecItemDelete(query); } } if (result != nullptr) CFRelease(result); if (itemMatch != nullptr) CFRelease(itemMatch); if (searchList != nullptr) CFRelease(searchList); if (query != nullptr) CFRelease(query); if (keyKeychain != nullptr) CFRelease(keyKeychain); *pOSStatus = status; return status == noErr; }
/* * Convert a keychain name (which may be NULL) into the CFArrayRef required * by SSLSetCertificate. This is a bare-bones example of this operation, * since it requires and assumes that there is exactly one SecIdentity * in the keychain - i.e., there is exactly one matching cert/private key * pair. A real world server would probably search a keychain for a SecIdentity * matching some specific criteria. */ CFArrayRef getSslCerts( const char *kcName, // may be NULL, i.e., use default bool encryptOnly, bool completeCertChain, const char *anchorFile, // optional trusted anchor SecKeychainRef *pKcRef) // RETURNED { #if 0 SecKeychainRef kcRef = nil; OSStatus ortn; *pKcRef = nil; /* pick a keychain */ if(kcName) { ortn = SecKeychainOpen(kcName, &kcRef); if(ortn) { printf("SecKeychainOpen returned %d.\n", (int)ortn); printf("Cannot open keychain at %s. Aborting.\n", kcName); return NULL; } } else { /* use default keychain */ ortn = SecKeychainCopyDefault(&kcRef); if(ortn) { printf("SecKeychainCopyDefault returned %d; aborting.\n", (int)ortn); return nil; } } *pKcRef = kcRef; return sslKcRefToCertArray(kcRef, encryptOnly, completeCertChain, anchorFile); #else SecCertificateRef cert = NULL; SecIdentityRef identity = NULL; CFMutableArrayRef certificates = NULL, result = NULL; CFMutableDictionaryRef certQuery = NULL, keyQuery = NULL, keyResult = NULL; SecTrustRef trust = NULL; SecKeyRef key = NULL; CFTypeRef pkdigest = NULL; // Find the first private key in the keychain and return both it's // attributes and a ref to it. require(keyQuery = CFDictionaryCreateMutable(NULL, 0, NULL, NULL), errOut); CFDictionaryAddValue(keyQuery, kSecClass, kSecClassKey); CFDictionaryAddValue(keyQuery, kSecAttrKeyClass, kSecAttrKeyClassPrivate); CFDictionaryAddValue(keyQuery, kSecReturnRef, kCFBooleanTrue); CFDictionaryAddValue(keyQuery, kSecReturnAttributes, kCFBooleanTrue); require_noerr(SecItemCopyMatching(keyQuery, (CFTypeRef *)&keyResult), errOut); require(key = (SecKeyRef)CFDictionaryGetValue(keyResult, kSecValueRef), errOut); require(pkdigest = CFDictionaryGetValue(keyResult, kSecAttrApplicationLabel), errOut); // Find the first certificate that has the same public key hash as the // returned private key and return it as a ref. require(certQuery = CFDictionaryCreateMutable(NULL, 0, NULL, NULL), errOut); CFDictionaryAddValue(certQuery, kSecClass, kSecClassCertificate); CFDictionaryAddValue(certQuery, kSecAttrPublicKeyHash, pkdigest); CFDictionaryAddValue(certQuery, kSecReturnRef, kCFBooleanTrue); require_noerr(SecItemCopyMatching(certQuery, (CFTypeRef *)&cert), errOut); // Create an identity from the key and certificate. require(identity = SecIdentityCreate(NULL, cert, key), errOut); // Build a (partial) certificate chain from cert require(certificates = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks), errOut); CFArrayAppendValue(certificates, cert); require_noerr(SecTrustCreateWithCertificates(certificates, NULL, &trust), errOut); SecTrustResultType tresult; require_noerr(SecTrustEvaluate(trust, &tresult), errOut); CFIndex certCount, ix; // We need at least 1 certificate require(certCount = SecTrustGetCertificateCount(trust), errOut); // Build a result where element 0 is the identity and the other elements // are the certs in the chain starting at the first intermediate up to the // anchor, if we found one, or as far as we were able to build the chain // if not. require(result = CFArrayCreateMutable(NULL, certCount, &kCFTypeArrayCallBacks), errOut); // We are commited to returning a result now, so do not use require below // this line without setting result to NULL again. CFArrayAppendValue(result, identity); for (ix = 1; ix < certCount; ++ix) { CFArrayAppendValue(result, SecTrustGetCertificateAtIndex(trust, ix)); } errOut: CFReleaseSafe(trust); CFReleaseSafe(certificates); CFReleaseSafe(identity); CFReleaseSafe(cert); CFReleaseSafe(certQuery); CFReleaseSafe(keyResult); CFReleaseSafe(keyQuery); return result; #endif }