Ejemplo n.º 1
0
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);
}