]> git.saurik.com Git - apple/security.git/blob - sec/securityd/Regressions/sd-70-engine.c
Security-55471.14.18.tar.gz
[apple/security.git] / sec / securityd / Regressions / sd-70-engine.c
1 //
2 // sd-70-engine.c
3 // sec
4 //
5 // Created by Michael Brouwer on 11/9/12.
6 // Copyright 2012 Apple Inc. All rights reserved.
7 //
8 //
9
10 // Test syncing between SecItemDataSource and SOSTestDataSource
11
12 #include <SecureObjectSync/SOSEngine.h>
13 #include <SecureObjectSync/SOSPeer.h>
14
15 #include "securityd_regressions.h"
16
17 #include <corecrypto/ccsha2.h>
18 #include <Security/SecBase64.h>
19 #include <utilities/SecCFWrappers.h>
20 #include <Security/SecItem.h>
21 #include <Security/SecItemPriv.h>
22 #include <securityd/SecItemServer.h>
23
24 #include <utilities/SecFileLocations.h>
25
26 #include <stdint.h>
27 #include "SOSTestDataSource.h"
28 #include "SOSTestTransport.h"
29
30 #include <AssertMacros.h>
31
32 static int kTestTestCount = 74;
33
34 // TODO: Make this shared.
35 static CFStringRef SOSMessageCopyDigestHex(CFDataRef message) {
36 uint8_t digest[CCSHA1_OUTPUT_SIZE];
37 ccdigest(ccsha1_di(), CFDataGetLength(message), CFDataGetBytePtr(message), digest);
38 CFMutableStringRef hex = CFStringCreateMutable(0, 2 * sizeof(digest));
39 for (unsigned int ix = 0; ix < sizeof(digest); ++ix) {
40 CFStringAppendFormat(hex, 0, CFSTR("%02X"), digest[ix]);
41 }
42 return hex;
43 }
44
45 static void testsync(const char *name, const char *test_directive, const char *test_reason, void (^aliceInit)(SOSDataSourceRef ds), void (^bobInit)(SOSDataSourceRef ds), CFStringRef msg, ...) {
46 CFErrorRef error = NULL;
47
48 /* Setup Alice and Bob's dataSources. */
49 SOSDataSourceFactoryRef aliceDataSourceFactory = SecItemDataSourceFactoryCreateDefault();
50 SOSDataSourceRef aliceDataSource = NULL;
51 CFArrayRef ds_names = aliceDataSourceFactory->copy_names(aliceDataSourceFactory);
52 if (ds_names && CFArrayGetCount(ds_names) > 0) {
53 CFStringRef name = CFArrayGetValueAtIndex(ds_names, 0);
54 ok (aliceDataSource = aliceDataSourceFactory->create_datasource(aliceDataSourceFactory, name, false, &error), "create datasource \"%@\" [error: %@]", name, error);
55 CFReleaseNull(error);
56 }
57 CFReleaseNull(ds_names);
58
59 SOSDataSourceRef bobDataSource = SOSTestDataSourceCreate();
60
61 /* Setup Alice engine and peer for Alice to talk to Bob */
62 SOSEngineRef aliceEngine;
63 ok(aliceEngine = SOSEngineCreate(aliceDataSource, &error), "create alice engine: %@", error);
64 CFReleaseNull(error);
65 CFStringRef bobID = CFStringCreateWithFormat(kCFAllocatorDefault, 0, CFSTR("Bob-%s"), name);
66
67 __block CFDataRef queued_message = NULL;
68
69 SOSPeerSendBlock enqueueMessage = ^bool (CFDataRef message, CFErrorRef *error) {
70 if (queued_message)
71 fail("We already had an unproccessed message");
72
73 queued_message = (CFDataRef) CFRetain(message);
74 return true;
75 };
76
77 CFDataRef (^dequeueMessage)() = ^CFDataRef () {
78 CFDataRef result = queued_message;
79 queued_message = NULL;
80
81 return result;
82 };
83
84 SOSPeerRef bobPeer;
85 ok(bobPeer = SOSPeerCreateSimple(bobID, kSOSPeerVersion, &error, enqueueMessage),
86 "create peer: %@", error);
87
88 /* Setup Bob engine and peer for Bob to talk to Alice */
89 SOSEngineRef bobEngine;
90 ok(bobEngine = SOSEngineCreate(bobDataSource, &error), "create bob engine: %@", error);
91 CFReleaseNull(error);
92 CFStringRef aliceID = CFStringCreateWithFormat(kCFAllocatorDefault, 0, CFSTR("Alice-%s"), name);
93
94 SOSPeerRef alicePeer;
95 ok(alicePeer = SOSPeerCreateSimple(aliceID, kSOSPeerVersion, &error, enqueueMessage),
96 "create peer: %@", error);
97 CFReleaseNull(error);
98
99 /* Now call provided setup blocks to populate the dataSources with
100 interesting stuff. */
101 aliceInit(aliceDataSource);
102 bobInit(bobDataSource);
103
104 /* Start syncing by making alice send the first message. */
105 ok(SOSEngineSyncWithPeer(aliceEngine, bobPeer, false, &error), "tell Alice sync with peer Bob");
106 CFDataRef message;
107
108 va_list msgs;
109 va_start(msgs, msg);
110
111 int msg_index = 0;
112 bool alice = false;
113 for (;;) {
114 message = dequeueMessage();
115 msg_index++;
116 /* We are expecting a message and msg is it's digest. */
117 if (message) {
118 CFStringRef messageDesc = SOSMessageCopyDescription(message);
119 CFStringRef messageDigestStr = SOSMessageCopyDigestHex(message);
120 if (msg) {
121 bool handeled = SOSEngineHandleMessage(alice ? aliceEngine : bobEngine, alice ? bobPeer : alicePeer, message, &error);
122 if (!CFEqual(messageDigestStr, msg)) {
123 if (handeled) {
124 fail("%s %s received message [%d] digest %@ != %@ %@", name, alice ? "Alice" : "Bob", msg_index, messageDigestStr, msg, messageDesc);
125 } else {
126 fail("%s %s failed to handle message [%d] digest %@ != %@ %@: %@", name, alice ? "Alice" : "Bob", msg_index, messageDigestStr, msg, messageDesc, error);
127 CFReleaseNull(error);
128 }
129 } else if (handeled) {
130 pass("%s %s handled message [%d] %@", name, alice ? "Alice" : "Bob", msg_index, messageDesc);
131 } else {
132 fail("%s %s failed to handle message [%d] %@: %@", name, alice ? "Alice" : "Bob", msg_index, messageDesc, error);
133 CFReleaseNull(error);
134 }
135 } else {
136 fail("%s %s sent extra message [%d] with digest %@: %@", name, alice ? "Bob" : "Alice", msg_index, messageDigestStr, messageDesc);
137 }
138 CFRelease(messageDigestStr);
139 CFRelease(messageDesc);
140 CFRelease(message);
141 } else {
142 if (msg) {
143 fail("%s %s expected message [%d] with digest %@, none received", name, alice ? "Alice" : "Bob", msg_index, msg);
144 }
145 }
146
147 if (msg) {
148 alice = !alice;
149 msg = va_arg(msgs, CFStringRef);
150 } else
151 break;
152 }
153
154 va_end(msgs);
155
156 SOSEngineDispose(aliceEngine); // Also disposes aliceDataSource
157 SOSPeerDispose(alicePeer);
158 CFReleaseSafe(aliceID);
159
160 SOSEngineDispose(bobEngine); // Also disposes bobDataSource
161 SOSPeerDispose(bobPeer);
162 CFReleaseSafe(bobID);
163
164 aliceDataSourceFactory->release(aliceDataSourceFactory);
165 }
166
167
168 static SOSObjectRef SOSDataSourceCopyObject(SOSDataSourceRef ds, SOSObjectRef match, CFErrorRef *error)
169 {
170 __block SOSObjectRef result = NULL;
171
172 CFDataRef digest = ds->copyDigest(match, error);
173 SOSManifestRef manifest = NULL;
174
175 require(digest, exit);
176
177 manifest = SOSManifestCreateWithData(digest, error);
178
179 ds->foreach_object(ds, manifest, error, ^ bool (SOSObjectRef object, CFErrorRef *error) {
180 if (result == NULL) {
181 result = object;
182 CFRetainSafe(result);
183 }
184
185 return true;
186 });
187
188 exit:
189 CFReleaseNull(manifest);
190 CFReleaseNull(digest);
191 return result;
192 }
193
194 static void synctests(void) {
195 #if 0
196 // TODO: Adding items gives us non predictable creation and mod dates so
197 // the message hashes can't be precomputed.
198 CFDictionaryRef item = CFDictionaryCreateForCFTypes
199 (0,
200 kSecClass, kSecClassGenericPassword,
201 kSecAttrAccessible, kSecAttrAccessibleWhenUnlocked,
202 kSecAttrSynchronizable, kCFBooleanTrue,
203 kSecAttrService, CFSTR("service"),
204 kSecAttrAccount, CFSTR("account"),
205 NULL);
206 SecItemAdd(item, NULL);
207 CFReleaseSafe(item);
208 #endif
209
210 SKIP:
211 {
212
213 #ifdef NO_SERVER
214 // Careful with this in !NO_SERVER, it'll destroy debug keychains.
215 WithPathInKeychainDirectory(CFSTR("keychain-2-debug.db"), ^(const char *keychain_path) {
216 unlink(keychain_path);
217 });
218
219 // Don't ever do this in !NO_SERVER, it'll destroy real keychains.
220 WithPathInKeychainDirectory(CFSTR("keychain-2.db"), ^(const char *keychain_path) {
221 unlink(keychain_path);
222 });
223
224 void kc_dbhandle_reset(void);
225 kc_dbhandle_reset();
226 #else
227 skip("Keychain not reset", kTestTestCount, false);
228 #endif
229
230 // Sync between 2 empty dataSources
231 testsync("sd_70_engine", test_directive, test_reason,
232 ^ (SOSDataSourceRef dataSource) {},
233 ^ (SOSDataSourceRef dataSource) {},
234 CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"),
235 CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"),
236 CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"),
237 NULL);
238
239 // Sync a dataSource with one object to an empty dataSource
240 testsync("sd_70_engine-alice1", test_directive, test_reason,
241 ^ (SOSDataSourceRef dataSource) {
242 CFErrorRef error = NULL;
243 SOSObjectRef object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("test_account"), CFSTR("test service"));
244 // TODO: Needs to be a SecDBItemRef for the SecItemDataSource...
245 ok(dataSource->add(dataSource, object, &error), "dataSource added object %@", error);
246 CFReleaseSafe(object);
247 CFReleaseNull(error);
248 },
249 ^ (SOSDataSourceRef dataSource) {},
250 CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"),
251 CFSTR("147B6C509908CC4A9FC4263973A842104A64CE01"),
252 CFSTR("019B494F3C06B48BB02C280AF1E19AD861A7003C"),
253 CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"),
254 NULL);
255
256 // Sync a dataSource with one object to another dataSource with the same object
257 testsync("sd_70_engine-alice1bob1", test_directive, test_reason,
258 ^ (SOSDataSourceRef dataSource) {
259 #if 0
260 CFErrorRef error = NULL;
261 // TODO: Needs to be a SecDBItemRef for the SecItemDataSource...
262 CFDictionaryRef object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("test_account"), CFSTR("test service"));
263 ok(dataSource->add(dataSource, object, &error), "dataSource added object %@", error);
264 CFReleaseSafe(object);
265 CFReleaseNull(error);
266 #endif
267 },
268 ^ (SOSDataSourceRef dataSource) {
269 CFErrorRef error = NULL;
270 SOSObjectRef object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("test_account"), CFSTR("test service"));
271 ok(dataSource->add(dataSource, object, &error), "dataSource added object %@", error);
272 CFReleaseSafe(object);
273 CFReleaseNull(error);
274 },
275 CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"),
276 CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"),
277 CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"),
278 NULL);
279
280 // Sync a dataSource with one object to another dataSource with the same object
281 testsync("sd_70_engine-alice1bob2", test_directive, test_reason,
282 ^ (SOSDataSourceRef dataSource) {
283 #if 0
284 CFErrorRef error = NULL;
285 // TODO: Needs to be a SecDBItemRef for the SecItemDataSource...
286 SOSObjectRef object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("test_account"), CFSTR("test service"));
287 ok(dataSource->add(dataSource, object, &error), "dataSource added object %@", error);
288 CFReleaseSafe(object);
289 CFReleaseNull(error);
290 #endif
291 },
292 ^ (SOSDataSourceRef dataSource) {
293 CFErrorRef error = NULL;
294 SOSObjectRef object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("test_account"), CFSTR("test service"));
295 ok(dataSource->add(dataSource, object, &error), "dataSource added object %@", error);
296 CFReleaseSafe(object);
297 object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("account1"), CFSTR("service1"));
298 ok(dataSource->add(dataSource, object, &error), "dataSource added object %@", error);
299 CFReleaseSafe(object);
300 CFReleaseNull(error);
301 },
302 CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"),
303 CFSTR("D4049A1063CFBF7CAF8424E13DE3CE926FF5856C"),
304 CFSTR("9624EA855BBED6B668868BB723443E804D04F6A1"),
305 CFSTR("063E097CCD4FEB7F3610ED12B3DA828467314846"),
306 CFSTR("D1B3944E3084425F41B2C2EA0BE82170E10AA37D"),
307 NULL);
308
309 // Sync a dataSource with a tombstone object to another dataSource with the same object
310 TODO: {
311 todo("<rdar://problem/14049022> Test case in sd-70-engine fails due to need for RowID");
312 testsync("sd_70_engine-update", test_directive, test_reason,
313 ^ (SOSDataSourceRef dataSource) {
314 CFErrorRef error = NULL;
315 const char *password = "password1";
316 CFDataRef data = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)password, strlen(password));
317 // TODO: Needs to be a SecDBItemRef for the SecItemDataSource...
318 SOSObjectRef object_to_find = SOSDataSourceCreateGenericItemWithData(dataSource, CFSTR("test_account"), CFSTR("test service"), true, NULL);
319 SOSObjectRef object = SOSDataSourceCopyObject(dataSource, object_to_find, &error);
320 SOSObjectRef old_object = NULL;
321 SKIP: {
322 skip("no object", 1, ok(object, "Finding object %@, error: %@", object_to_find, error));
323 CFReleaseNull(data);
324 // TODO: Needs to be a SecDBItemRef for the SecItemDataSource...
325 old_object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("test_account"), CFSTR("test service"));
326 ok(dataSource->add(dataSource, object, &error), "dataSource update object %@", error);
327 }
328 CFReleaseSafe(data);
329 CFReleaseSafe(old_object);
330 CFReleaseSafe(object);
331 CFReleaseNull(error);
332 },
333 ^ (SOSDataSourceRef dataSource) {
334 CFErrorRef error = NULL;
335 SOSObjectRef object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("test_account"), CFSTR("test service"));
336 ok(dataSource->add(dataSource, object, &error), "dataSource added object %@", error);
337 CFReleaseSafe(object);
338 object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("account1"), CFSTR("service1"));
339 ok(dataSource->add(dataSource, object, &error), "dataSource added object %@", error);
340 CFReleaseSafe(object);
341 CFReleaseNull(error);
342 },
343 CFSTR("5D07A221A152D6D6C5F1919189F259A7278A08C5"),
344 CFSTR("D4049A1063CFBF7CAF8424E13DE3CE926FF5856C"),
345 CFSTR("137FD34E9BF11B4BA0620E8EBFAB8576BCCCF294"),
346 CFSTR("5D07A221A152D6D6C5F1919189F259A7278A08C5"),
347 NULL);
348 }
349
350 // Sync a dataSource with one object to another dataSource with the same object
351 testsync("sd_70_engine-foreign-add", test_directive, test_reason,
352 ^ (SOSDataSourceRef dataSource) {
353 },
354 ^ (SOSDataSourceRef dataSource) {
355 CFErrorRef error = NULL;
356 const char *password = "password1";
357 CFDataRef data = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)password, strlen(password));
358 SOSObjectRef object = SOSDataSourceCreateGenericItemWithData(dataSource, CFSTR("test_account"), CFSTR("test service"), false, data);
359 CFReleaseSafe(data);
360 ok(dataSource->add(dataSource, object, &error), "dataSource added object %@", error);
361 CFReleaseSafe(object);
362 CFReleaseNull(error);
363 object = SOSDataSourceCreateGenericItem(dataSource, CFSTR("account1"), CFSTR("service1"));
364 ok(dataSource->add(dataSource, object, &error), "dataSource added object %@", error);
365 CFReleaseSafe(object);
366 CFReleaseNull(error);
367 },
368 CFSTR("D1B3944E3084425F41B2C2EA0BE82170E10AA37D"),
369 CFSTR("607EEF976943FD781CFD2B3850E6DC7979AA61EF"),
370 CFSTR("28434CD1B90CC205460557CAC03D7F12067F2329"),
371 CFSTR("D1B3944E3084425F41B2C2EA0BE82170E10AA37D"),
372 NULL);
373 }
374 }
375
376 int sd_70_engine(int argc, char *const *argv)
377 {
378 plan_tests(kTestTestCount);
379
380 synctests();
381
382 return 0;
383 }