static VALUE rb_keychain_item_save(VALUE self){ SecKeychainItemRef keychainItem = NULL; Data_Get_Struct(self, struct OpaqueSecKeychainItemRef, keychainItem); CFMutableDictionaryRef query = sec_query_identifying_item(keychainItem); CFMutableDictionaryRef attributes = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); VALUE rb_attributes = rb_ivar_get(self, rb_intern("@attributes")); VALUE attributes_wrapper = Data_Wrap_Struct(rb_cPointerWrapper, NULL, NULL, attributes); rb_block_call(rb_attributes, rb_intern("each"), 0, NULL, RUBY_METHOD_FUNC(copy_attributes_for_update), (VALUE)attributes_wrapper); VALUE newPassword = rb_ivar_get(self, rb_intern("@unsaved_password")); if(!NIL_P(newPassword)){ rb_add_value_to_cf_dictionary(attributes, kSecValueData, newPassword); } CFStringRef cfclass = rb_copy_item_class(keychainItem); CFDictionarySetValue(query, kSecClass, cfclass); CFRelease(cfclass); OSStatus result = SecItemUpdate(query, attributes); CFRelease(query); CFRelease(attributes); CheckOSStatusOrRaise(result); rb_keychain_item_reload(self); return self; }
bool SOSItemUpdateOrAdd(CFStringRef service, CFStringRef accessibility, CFDataRef data, CFErrorRef *error) { CFDictionaryRef query = SOSItemCopyQueryForSyncItems(service, false); CFDictionaryRef update = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, kSecValueData, data, kSecAttrAccessible, accessibility, NULL); OSStatus saveStatus = SecItemUpdate(query, update); if (errSecItemNotFound == saveStatus) { CFMutableDictionaryRef add = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, query); CFDictionaryForEach(update, ^(const void *key, const void *value) { CFDictionaryAddValue(add, key, value); });
/* 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_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); }