1
2//
3//  si-72-syncableitems.c
4//  regressions
5//
6//  Created by Ken McLeod on 5/18/13.
7//
8//
9#include <CoreFoundation/CoreFoundation.h>
10#include <Security/Security.h>
11#include <Security/SecItemPriv.h>
12#include <Security/SecInternal.h>
13#include <utilities/array_size.h>
14
15#include "Security_regressions.h"
16
17static void tests(void)
18{
19    CFUUIDRef uuid = CFUUIDCreate(0);
20	const CFStringRef uuidstr = CFUUIDCreateString(0, uuid);
21	const CFStringRef account = CFStringCreateWithFormat(NULL, NULL, CFSTR("Test Account %@"), uuidstr);
22	const CFStringRef service = CFSTR("Test Service");
23	const CFStringRef label = CFSTR("Test Synchronizable Item");
24	const CFStringRef comment = CFSTR("Test Comment");
25	const CFDataRef passwordData = CFDataCreate(NULL, (const UInt8*)"Test", (CFIndex)5);
26
27    CFReleaseSafe(uuid);
28    CFReleaseSafe(uuidstr);
29
30	CFDictionaryRef query = NULL;
31	CFDictionaryRef attrs = NULL;
32	CFDictionaryRef result = NULL;
33
34	/* Test adding a synchronizable item */
35	{
36		const void *keys[] = {
37			kSecClass, kSecAttrLabel, kSecAttrComment, kSecAttrAccount, kSecAttrService,
38			kSecAttrSynchronizable,
39			kSecValueData, kSecReturnAttributes };
40		const void *values[] = {
41			kSecClassGenericPassword, label, comment, account, service,
42			kCFBooleanTrue,
43			passwordData, kCFBooleanTrue };
44
45		attrs = CFDictionaryCreate(NULL, keys, values,
46			array_size(keys),
47			&kCFTypeDictionaryKeyCallBacks,
48			&kCFTypeDictionaryValueCallBacks);
49
50		is_status(SecItemAdd(attrs, (CFTypeRef *)&result),
51				errSecSuccess, "SecItemAdd sync=true");
52
53		CFReleaseSafe(attrs);
54		CFReleaseNull(result);
55	}
56
57	/* Test finding the synchronizable item we just added, using sync=true */
58	{
59		const void *keys[] = {
60			kSecClass, // class attribute is required
61			kSecAttrAccount, kSecAttrService, // we'll look up by account and service, which determine uniqueness
62			kSecAttrSynchronizable, // we want to get synchronizable results
63			kSecReturnAttributes };
64		const void *values[] = {
65			kSecClassGenericPassword,
66			account, service,
67			kCFBooleanTrue, // only return synchronizable results
68			kCFBooleanTrue };
69
70		query = CFDictionaryCreate(NULL, keys, values,
71			array_size(keys),
72			&kCFTypeDictionaryKeyCallBacks,
73			&kCFTypeDictionaryValueCallBacks);
74
75		is_status(SecItemCopyMatching(query, (CFTypeRef *)&result),
76			errSecSuccess, "SecItemCopyMatching sync=true");
77
78		CFReleaseSafe(query);
79		CFReleaseNull(result);
80	}
81
82	/* Test finding the synchronizable item we just added, using sync=any */
83	{
84		const void *keys[] = {
85			kSecClass, // class attribute is required
86			kSecAttrAccount, kSecAttrService, // we'll look up by account and service, which determine uniqueness
87			kSecAttrSynchronizable, // we want to get synchronizable results
88			kSecReturnAttributes };
89		const void *values[] = {
90			kSecClassGenericPassword,
91			account, service,
92			kSecAttrSynchronizableAny, // return any match, regardless of whether it is synchronizable
93			kCFBooleanTrue };
94
95		query = CFDictionaryCreate(NULL, keys, values,
96			array_size(keys),
97			&kCFTypeDictionaryKeyCallBacks,
98			&kCFTypeDictionaryValueCallBacks);
99
100		is_status(SecItemCopyMatching(query, (CFTypeRef *)&result),
101			errSecSuccess, "SecItemCopyMatching sync=any");
102
103		CFReleaseSafe(query);
104		CFReleaseNull(result);
105	}
106
107	/* Test updating the synchronizable item */
108	{
109		const void *keys[] = {
110			kSecClass, // class attribute is required
111			kSecAttrAccount, kSecAttrService, // we'll look up by account and service, which determine uniqueness
112			kSecAttrSynchronizable }; // we want synchronizable results
113		const void *values[] = {
114			kSecClassGenericPassword,
115			account, service,
116			kCFBooleanTrue }; // we only want to find the synchronizable item here, not a non-synchronizable one
117
118		query = CFDictionaryCreate(NULL, keys, values,
119			array_size(keys),
120			&kCFTypeDictionaryKeyCallBacks,
121			&kCFTypeDictionaryValueCallBacks);
122
123		const void *update_keys[] = { kSecAttrComment };
124		const void *update_values[] = { CFSTR("Updated Comment") };
125		attrs = CFDictionaryCreate(NULL, update_keys, update_values,
126			array_size(update_keys),
127			&kCFTypeDictionaryKeyCallBacks,
128			&kCFTypeDictionaryValueCallBacks);
129
130		is_status(SecItemUpdate(query, attrs),
131			errSecSuccess, "SecItemUpdate sync=true");
132
133		CFReleaseSafe(query);
134		CFReleaseSafe(attrs);
135	}
136
137	/* Test finding the updated item with its new attribute */
138	{
139		const void *keys[] = {
140			kSecClass, // class attribute is required
141			kSecAttrAccount, kSecAttrService, // we'll look up by account and service, which determine uniqueness
142			kSecAttrComment, // also search on the attr we just changed, so we know we've found the updated item
143			kSecAttrSynchronizable }; // we want synchronizable results
144		const void *values[] = {
145			kSecClassGenericPassword,
146			account, service,
147			CFSTR("Updated Comment"),
148			kCFBooleanTrue }; // we only want to find the synchronizable item here, not a non-synchronizable one
149
150		query = CFDictionaryCreate(NULL, keys, values,
151			array_size(keys),
152			&kCFTypeDictionaryKeyCallBacks,
153			&kCFTypeDictionaryValueCallBacks);
154
155		is_status(SecItemCopyMatching(query, (CFTypeRef *)&result),
156			errSecSuccess, "SecItemCopyMatching post-update");
157
158		CFReleaseSafe(result);
159		// re-use query in next test...
160	}
161
162	/* Test deleting the item */
163	{
164		is_status(SecItemDelete(query), errSecSuccess, "SecItemDelete sync=true");
165
166		CFReleaseSafe(query);
167	}
168}
169
170int si_72_syncableitems(int argc, char * const *argv)
171{
172	plan_tests(6);
173	tests();
174
175	return 0;
176}
177