]> git.saurik.com Git - apple/security.git/blob - sec/SOSCircle/Regressions/sc-120-cloudcircle.c
Security-55471.14.8.tar.gz
[apple/security.git] / sec / SOSCircle / Regressions / sc-120-cloudcircle.c
1 /*
2 * sc-01-create.c
3 *
4 * Created by Mitch Adler on 1/25/121.
5 * Copyright 2012 Apple Inc. All rights reserved.
6 *
7 */
8
9 // /AppleInternal/Applications/SecurityTests.app/SecurityTests sc_120_cloudcircle -v -- -i alice
10 // /AppleInternal/Applications/SecurityTests.app/SecurityTests sc_120_cloudcircle -v -- -i bob
11
12 #include <Security/SecBase.h>
13 #include <Security/SecItem.h>
14 #include <Security/SecKey.h>
15 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
16 #include <Security/SecRandom.h>
17 #endif
18
19 #include <SecureObjectSync/SOSAccount.h>
20 #include <SecureObjectSync/SOSCloudCircle.h>
21 #include <SecureObjectSync/SOSCloudCircleInternal.h>
22 #include <SecureObjectSync/SOSPeerInfo.h>
23 #include <SecureObjectSync/SOSInternal.h>
24 #include "SOSTestDataSource.h"
25 #include <CKBridge/SOSCloudKeychainClient.h>
26
27 #include <utilities/debugging.h>
28
29 #include <utilities/SecCFWrappers.h>
30 #include <utilities/iOSforOSX.h>
31
32 #include <CoreFoundation/CoreFoundation.h>
33
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <getopt.h>
37
38 #include <notify.h>
39
40 #include "SOSRegressionUtilities.h"
41
42 #include "SOSCircle_regressions.h"
43 #include "SecureObjectSync/Imported/SOSCloudCircleServer.h"
44
45 #ifdef NO_SERVER
46 #if TARGET_OS_EMBEDDED || TARGET_IPHONE_SIMULATOR
47 #include <securityd/SOSCloudCircleServer.h>
48 #else
49 #warning "NO_SERVER doesn't really work on OSX"
50 #endif
51 #endif
52
53 static CFStringRef kCircleName = CFSTR("Global Circle");
54
55 static CFStringRef sAliceReady = CFSTR("Alice-Ready");
56 static CFStringRef sBobReady = CFSTR("Bob-Ready");
57
58 static void SOSCloudKeychainClearAllSync()
59 {
60 dispatch_semaphore_t waitSemaphore = dispatch_semaphore_create(0);
61 SOSCloudKeychainClearAll(dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
62 ^(CFDictionaryRef returnedValues __unused, CFErrorRef error)
63 {
64 CFReleaseSafe(error);
65 dispatch_semaphore_signal(waitSemaphore);
66 });
67 dispatch_semaphore_wait(waitSemaphore, DISPATCH_TIME_FOREVER);
68 dispatch_release(waitSemaphore);
69 }
70
71 static void ClearAndSynchronize()
72 {
73 dispatch_queue_t global_queue = dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
74 dispatch_semaphore_t bob_ready_semaphore = dispatch_semaphore_create(0);
75
76 const CFIndex nonceByteCount = 10;
77 CFMutableDataRef nonce = CFDataCreateMutable(kCFAllocatorDefault, nonceByteCount);
78 CFDataSetLength(nonce, nonceByteCount);
79 SecRandomCopyBytes(kSecRandomDefault, CFDataGetLength(nonce), CFDataGetMutableBytePtr(nonce));
80
81 dispatch_queue_t notification_queue = dispatch_queue_create("sync notification queue", DISPATCH_QUEUE_SERIAL);
82
83 CloudItemsChangedBlock notification_block = ^ (CFDictionaryRef returnedValues)
84 {
85 CFRetain(returnedValues);
86 dispatch_async(notification_queue, ^{
87 CFTypeRef bobReadyValue = CFDictionaryGetValue(returnedValues, sBobReady);
88 if (isData(bobReadyValue) && CFEqual(bobReadyValue, nonce)) {
89 SOSCloudKeychainClearAllSync();
90
91 pass("signalling");
92 dispatch_semaphore_signal(bob_ready_semaphore);
93 } else {
94 pass("Ignoring change: %@", returnedValues);
95 }
96 CFReleaseSafe(returnedValues);
97 });
98 };
99
100 CloudKeychainReplyBlock reply_block = ^ (CFDictionaryRef returnedValues, CFErrorRef error)
101 {
102 if (CFDictionaryGetCount(returnedValues) != 0)
103 notification_block(returnedValues);
104 };
105
106 pass("Clearing");
107 SOSCloudKeychainClearAllSync();
108
109 CFArrayRef bobKey = CFArrayCreateForCFTypes(kCFAllocatorDefault, sBobReady, NULL);
110 SOSCloudKeychainRegisterKeysAndGet(bobKey, global_queue, reply_block, notification_block);
111
112 CFStringRef description = SOSInterestListCopyDescription(bobKey);
113 pass("%@", description);
114
115 CFReleaseNull(description);
116 CFReleaseNull(bobKey);
117
118 CFDictionaryRef changes = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, sAliceReady, nonce, NULL);
119 SOSCloudKeychainPutObjectsInCloud(changes, global_queue, NULL);
120
121 description = SOSChangesCopyDescription(changes, true);
122 pass("%@", description);
123 CFReleaseNull(description);
124
125 pass("Waiting");
126 dispatch_semaphore_wait(bob_ready_semaphore, DISPATCH_TIME_FOREVER);
127 dispatch_release(bob_ready_semaphore);
128
129 pass("Continuing");
130
131 CFErrorRef error = NULL;
132 CFArrayRef no_keys = CFArrayCreateForCFTypes(kCFAllocatorDefault, NULL);
133 SOSCloudKeychainUpdateKeys(false, no_keys, no_keys, no_keys, &error);
134
135 SOSCloudKeychainSetItemsChangedBlock(NULL);
136 CFReleaseSafe(no_keys);
137 CFReleaseSafe(error);
138
139
140 CFReleaseNull(changes);
141 }
142
143 static void WaitForSynchronization()
144 {
145 dispatch_queue_t global_queue = dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
146 dispatch_semaphore_t alice_ready_semaphore = dispatch_semaphore_create(0);
147 dispatch_queue_t notification_queue = dispatch_queue_create("sync notification queue", DISPATCH_QUEUE_SERIAL);
148
149 __block CFDataRef foundNonce = NULL;
150 CloudItemsChangedBlock notification_block = ^ (CFDictionaryRef returnedValues)
151 {
152 CFRetain(returnedValues);
153 dispatch_async(notification_queue, ^{
154 CFTypeRef aliceReadyValue = CFDictionaryGetValue(returnedValues, sAliceReady);
155 if (isData(aliceReadyValue)) {
156 foundNonce = (CFDataRef) aliceReadyValue;
157 CFRetain(foundNonce);
158 pass("signalling for: %@", foundNonce);
159
160 dispatch_semaphore_signal(alice_ready_semaphore);
161 }
162 CFReleaseSafe(returnedValues);
163 });
164 };
165
166 CloudKeychainReplyBlock reply_block = ^ (CFDictionaryRef returnedValues, CFErrorRef error)
167 {
168 if (CFDictionaryGetCount(returnedValues) != 0)
169 notification_block(returnedValues);
170 };
171
172 CFArrayRef aliceKey = CFArrayCreateForCFTypes(kCFAllocatorDefault, sAliceReady, NULL);
173 SOSCloudKeychainRegisterKeysAndGet(aliceKey, global_queue, reply_block, notification_block);
174
175 CFStringRef description = SOSInterestListCopyDescription(aliceKey);
176 pass("%@", description);
177 CFReleaseNull(description);
178
179 pass("Waiting");
180 dispatch_semaphore_wait(alice_ready_semaphore, DISPATCH_TIME_FOREVER);
181 dispatch_release(alice_ready_semaphore);
182 pass("Continuing");
183
184 CFDictionaryRef changes = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, sBobReady, foundNonce, NULL);
185 SOSCloudKeychainPutObjectsInCloud(changes, global_queue, NULL);
186 CFReleaseSafe(changes);
187
188 CFReleaseSafe(foundNonce);
189 CFReleaseSafe(aliceKey);
190 }
191
192 static CFStringRef circleKey = CFSTR("Circle");
193
194 #ifdef NO_SERVER
195 static SOSDataSourceRef SetupTestFactory()
196 {
197 static SOSDataSourceRef our_data_source;
198
199 our_data_source = SOSTestDataSourceCreate();
200
201 SOSKeychainAccountSetFactoryForAccount(^ {
202 SOSDataSourceFactoryRef our_data_source_factory = SOSTestDataSourceFactoryCreate();
203 SOSTestDataSourceFactoryAddDataSource(our_data_source_factory, circleKey, our_data_source);
204 return our_data_source_factory;
205 });
206
207 return our_data_source;
208 }
209 #endif
210
211 static void PurgeAndReload()
212 {
213 #if 0
214 CFErrorRef error = NULL;
215 ok(SOSKeychainSaveAccountDataAndPurge(&error), "Purged");
216 CFReleaseNull(error);
217
218 ok(SOSKeychainAccountGetSharedAccount(), "Got Shared: %@", SOSKeychainAccountGetSharedAccount());
219 #endif
220 }
221
222 #ifndef NO_SERVER
223 #define SOSKeychainAccountGetSharedAccount() NULL
224 #endif
225
226 #define kAliceTestCount 100
227 static void AliceTests()
228 {
229 plan_tests(kAliceTestCount);
230
231 dispatch_semaphore_t notification_signal = dispatch_semaphore_create(0);
232 int token;
233 notify_register_dispatch(kSOSCCCircleChangedNotification, &token,
234 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
235 ^(int token) {
236 dispatch_semaphore_signal(notification_signal);
237 });
238
239 SOSCloudKeychainSetCallbackMethodXPC(); // call this first
240 ClearAndSynchronize();
241
242 #ifdef NO_SERVER
243 SOSDataSourceRef our_test_data_source = SetupTestFactory();
244 #endif
245 CFErrorRef error = NULL;
246
247 ok(SOSCCResetToOffering(&error), "Reset: %@ [%@]", SOSKeychainAccountGetSharedAccount(), error);
248 CFReleaseNull(error);
249
250 PurgeAndReload();
251
252 CFArrayRef applicants = NULL;
253 do {
254 dispatch_semaphore_wait(notification_signal, DISPATCH_TIME_FOREVER);
255 applicants = SOSCCCopyApplicantPeerInfo(&error);
256 CFReleaseNull(error);
257 } while (CFArrayGetCount(applicants) == 0);
258 pass("Waited long enough");
259
260 is(CFArrayGetCount(applicants), 1, "Bob should be applying");
261 CFReleaseNull(error);
262
263 ok(SOSCCAcceptApplicants(applicants, &error), "Accepted all applicants: %@", error);
264 CFReleaseNull(error);
265 CFReleaseSafe(applicants);
266
267 PurgeAndReload();
268
269 sleep(180);
270 pass("Waited long enough again");
271
272 #ifdef NO_SERVER
273 CFDictionaryRef data = SOSTestDataSourceGetDatabase(our_test_data_source);
274 is(CFDictionaryGetCount(data), 1, "Should have gotten bob's one");
275 #endif
276 }
277
278 #define kBobTestCount 100
279 static void BobTests()
280 {
281 plan_tests(kBobTestCount);
282
283 dispatch_semaphore_t notification_signal = dispatch_semaphore_create(0);
284 int token;
285 notify_register_dispatch(kSOSCCCircleChangedNotification, &token,
286 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
287 ^(int token) {
288 dispatch_semaphore_signal(notification_signal);
289 });
290
291 SOSCloudKeychainSetCallbackMethodXPC(); // call this first
292 WaitForSynchronization();
293
294 #ifdef NO_SERVER
295 SOSDataSourceRef our_test_data_source = SetupTestFactory();
296 #endif
297
298 CFErrorRef error = NULL;
299
300 #ifdef NO_SERVER
301 SOSObjectRef firstObject = SOSDataSourceCreateGenericItem(our_test_data_source, CFSTR("1234"), CFSTR("service"));
302 SOSTestDataSourceAddObject(our_test_data_source, firstObject, &error);
303 #endif
304
305 CFReleaseNull(error);
306
307 is(SOSCCThisDeviceIsInCircle(&error), kSOSCCCircleAbsent, "Shouldn't be a circle: %@", error);
308 CFReleaseNull(error);
309
310 PurgeAndReload();
311
312 CFArrayRef peers = NULL;
313 do {
314 dispatch_semaphore_wait(notification_signal, DISPATCH_TIME_FOREVER);
315 peers = SOSCCCopyPeerPeerInfo(&error);
316 CFReleaseNull(error);
317 } while (CFArrayGetCount(peers) == 0);
318
319 pass("Peer arrived: %@", SOSKeychainAccountGetSharedAccount());
320
321 is(CFArrayGetCount(peers), 1, "Only Alice should be there");
322 CFReleaseSafe(peers);
323
324 ok(SOSCCRequestToJoinCircle(&error), "Join circles: %@ [%@]", SOSKeychainAccountGetSharedAccount(), error);
325 CFReleaseNull(error);
326
327 PurgeAndReload();
328
329 do {
330 dispatch_semaphore_wait(notification_signal, DISPATCH_TIME_FOREVER);
331
332 } while (SOSCCThisDeviceIsInCircle(&error) != kSOSCCInCircle);
333 pass("Was admitted: %@ [%@]", SOSKeychainAccountGetSharedAccount(), error);
334 CFReleaseNull(error);
335
336 is(SOSCCThisDeviceIsInCircle(&error), kSOSCCInCircle, "Should be in circle: %@", error);
337 CFReleaseNull(error);
338
339 PurgeAndReload();
340
341 // Sync
342 sleep(120);
343 pass("Waited long enough again: %@", SOSKeychainAccountGetSharedAccount());
344
345 #ifdef NO_SERVER
346 CFDictionaryRef data = SOSTestDataSourceGetDatabase(our_test_data_source);
347 is(CFDictionaryGetCount(data), 1, "Only have one");
348 #endif
349 }
350
351
352 static const struct option options[] =
353 {
354 { "identity", optional_argument, NULL, 'i' },
355 { }
356 };
357
358
359 int sc_120_cloudcircle(int argc, char *const *argv)
360 {
361 char *identity = NULL;
362 extern char *optarg;
363 int arg, argSlot;
364
365 bool isAlice = false;
366
367 while (argSlot = -1, (arg = getopt_long(argc, (char * const *)argv, "i:vC", options, &argSlot)) != -1)
368 switch (arg)
369 {
370 case 'i':
371 identity = (char *)(optarg);
372 break;
373 default:
374 fail("arg: %s", optarg);
375 break;
376 }
377
378 if (identity)
379 {
380 if (!strcmp(identity, "alice"))
381 isAlice = true;
382 }
383
384 if (isAlice)
385 AliceTests();
386 else
387 BobTests();
388
389 return 0;
390
391 }