1/*
2 * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25//
26//  si-72-syncableitems.c
27//  regressions
28//
29//
30//
31#include <CoreFoundation/CoreFoundation.h>
32#include <Security/Security.h>
33#include <Security/SecItemPriv.h>
34#include <Security/SecInternal.h>
35#include <utilities/array_size.h>
36
37#include "Security_regressions.h"
38
39static void tests(void)
40{
41    CFUUIDRef uuid = CFUUIDCreate(0);
42	const CFStringRef uuidstr = CFUUIDCreateString(0, uuid);
43	const CFStringRef account = CFStringCreateWithFormat(NULL, NULL, CFSTR("Test Account %@"), uuidstr);
44	const CFStringRef service = CFSTR("Test Service");
45	const CFStringRef label = CFSTR("Test Synchronizable Item");
46	const CFStringRef comment = CFSTR("Test Comment");
47	const CFDataRef passwordData = CFDataCreate(NULL, (const UInt8*)"Test", (CFIndex)5);
48
49    CFReleaseSafe(uuid);
50    CFReleaseSafe(uuidstr);
51
52	CFDictionaryRef query = NULL;
53	CFDictionaryRef attrs = NULL;
54	CFDictionaryRef result = NULL;
55
56	/* Test adding a synchronizable item */
57	{
58		const void *keys[] = {
59			kSecClass, kSecAttrLabel, kSecAttrComment, kSecAttrAccount, kSecAttrService,
60			kSecAttrSynchronizable,
61			kSecValueData, kSecReturnAttributes };
62		const void *values[] = {
63			kSecClassGenericPassword, label, comment, account, service,
64			kCFBooleanTrue,
65			passwordData, kCFBooleanTrue };
66
67		attrs = CFDictionaryCreate(NULL, keys, values,
68			array_size(keys),
69			&kCFTypeDictionaryKeyCallBacks,
70			&kCFTypeDictionaryValueCallBacks);
71
72		is_status(SecItemAdd(attrs, (CFTypeRef *)&result),
73				errSecSuccess, "SecItemAdd sync=true");
74
75		CFReleaseSafe(attrs);
76		CFReleaseNull(result);
77	}
78
79	/* Test finding the synchronizable item we just added, using sync=true */
80	{
81		const void *keys[] = {
82			kSecClass, // class attribute is required
83			kSecAttrAccount, kSecAttrService, // we'll look up by account and service, which determine uniqueness
84			kSecAttrSynchronizable, // we want to get synchronizable results
85			kSecReturnAttributes };
86		const void *values[] = {
87			kSecClassGenericPassword,
88			account, service,
89			kCFBooleanTrue, // only return synchronizable results
90			kCFBooleanTrue };
91
92		query = CFDictionaryCreate(NULL, keys, values,
93			array_size(keys),
94			&kCFTypeDictionaryKeyCallBacks,
95			&kCFTypeDictionaryValueCallBacks);
96
97		is_status(SecItemCopyMatching(query, (CFTypeRef *)&result),
98			errSecSuccess, "SecItemCopyMatching sync=true");
99
100		CFReleaseSafe(query);
101		CFReleaseNull(result);
102	}
103
104	/* Test finding the synchronizable item we just added, using sync=any */
105	{
106		const void *keys[] = {
107			kSecClass, // class attribute is required
108			kSecAttrAccount, kSecAttrService, // we'll look up by account and service, which determine uniqueness
109			kSecAttrSynchronizable, // we want to get synchronizable results
110			kSecReturnAttributes };
111		const void *values[] = {
112			kSecClassGenericPassword,
113			account, service,
114			kSecAttrSynchronizableAny, // return any match, regardless of whether it is synchronizable
115			kCFBooleanTrue };
116
117		query = CFDictionaryCreate(NULL, keys, values,
118			array_size(keys),
119			&kCFTypeDictionaryKeyCallBacks,
120			&kCFTypeDictionaryValueCallBacks);
121
122		is_status(SecItemCopyMatching(query, (CFTypeRef *)&result),
123			errSecSuccess, "SecItemCopyMatching sync=any");
124
125		CFReleaseSafe(query);
126		CFReleaseNull(result);
127	}
128
129	/* Test updating the synchronizable item */
130	{
131		const void *keys[] = {
132			kSecClass, // class attribute is required
133			kSecAttrAccount, kSecAttrService, // we'll look up by account and service, which determine uniqueness
134			kSecAttrSynchronizable }; // we want synchronizable results
135		const void *values[] = {
136			kSecClassGenericPassword,
137			account, service,
138			kCFBooleanTrue }; // we only want to find the synchronizable item here, not a non-synchronizable one
139
140		query = CFDictionaryCreate(NULL, keys, values,
141			array_size(keys),
142			&kCFTypeDictionaryKeyCallBacks,
143			&kCFTypeDictionaryValueCallBacks);
144
145		const void *update_keys[] = { kSecAttrComment };
146		const void *update_values[] = { CFSTR("Updated Comment") };
147		attrs = CFDictionaryCreate(NULL, update_keys, update_values,
148			array_size(update_keys),
149			&kCFTypeDictionaryKeyCallBacks,
150			&kCFTypeDictionaryValueCallBacks);
151
152		is_status(SecItemUpdate(query, attrs),
153			errSecSuccess, "SecItemUpdate sync=true");
154
155		CFReleaseSafe(query);
156		CFReleaseSafe(attrs);
157	}
158
159	/* Test finding the updated item with its new attribute */
160	{
161		const void *keys[] = {
162			kSecClass, // class attribute is required
163			kSecAttrAccount, kSecAttrService, // we'll look up by account and service, which determine uniqueness
164			kSecAttrComment, // also search on the attr we just changed, so we know we've found the updated item
165			kSecAttrSynchronizable }; // we want synchronizable results
166		const void *values[] = {
167			kSecClassGenericPassword,
168			account, service,
169			CFSTR("Updated Comment"),
170			kCFBooleanTrue }; // we only want to find the synchronizable item here, not a non-synchronizable one
171
172		query = CFDictionaryCreate(NULL, keys, values,
173			array_size(keys),
174			&kCFTypeDictionaryKeyCallBacks,
175			&kCFTypeDictionaryValueCallBacks);
176
177		is_status(SecItemCopyMatching(query, (CFTypeRef *)&result),
178			errSecSuccess, "SecItemCopyMatching post-update");
179
180		CFReleaseSafe(result);
181		// re-use query in next test...
182	}
183
184	/* Test deleting the item */
185	{
186		is_status(SecItemDelete(query), errSecSuccess, "SecItemDelete sync=true");
187
188		CFReleaseSafe(query);
189	}
190}
191
192int si_72_syncableitems(int argc, char * const *argv)
193{
194	plan_tests(6);
195	tests();
196
197	return 0;
198}
199