4 * Created by Mitch Adler on 1/25/121.
5 * Copyright 2012 Apple Inc. All rights reserved.
9 // /AppleInternal/Applications/SecurityTests.app/SecurityTests sc_120_cloudcircle -v -- -i alice
10 // /AppleInternal/Applications/SecurityTests.app/SecurityTests sc_120_cloudcircle -v -- -i bob
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>
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>
27 #include <utilities/debugging.h>
29 #include <utilities/SecCFWrappers.h>
30 #include <utilities/iOSforOSX.h>
32 #include <CoreFoundation/CoreFoundation.h>
40 #include "SOSRegressionUtilities.h"
42 #include "SOSCircle_regressions.h"
43 #include "SecureObjectSync/Imported/SOSCloudCircleServer.h"
46 #if TARGET_OS_EMBEDDED || TARGET_IPHONE_SIMULATOR
47 #include <securityd/SOSCloudCircleServer.h>
49 #warning "NO_SERVER doesn't really work on OSX"
53 static CFStringRef kCircleName
= CFSTR("Global Circle");
55 static CFStringRef sAliceReady
= CFSTR("Alice-Ready");
56 static CFStringRef sBobReady
= CFSTR("Bob-Ready");
58 static void SOSCloudKeychainClearAllSync()
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
)
65 dispatch_semaphore_signal(waitSemaphore
);
67 dispatch_semaphore_wait(waitSemaphore
, DISPATCH_TIME_FOREVER
);
68 dispatch_release(waitSemaphore
);
71 static void ClearAndSynchronize()
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);
76 const CFIndex nonceByteCount
= 10;
77 CFMutableDataRef nonce
= CFDataCreateMutable(kCFAllocatorDefault
, nonceByteCount
);
78 CFDataSetLength(nonce
, nonceByteCount
);
79 SecRandomCopyBytes(kSecRandomDefault
, CFDataGetLength(nonce
), CFDataGetMutableBytePtr(nonce
));
81 dispatch_queue_t notification_queue
= dispatch_queue_create("sync notification queue", DISPATCH_QUEUE_SERIAL
);
83 CloudItemsChangedBlock notification_block
= ^ (CFDictionaryRef returnedValues
)
85 CFRetain(returnedValues
);
86 dispatch_async(notification_queue
, ^{
87 CFTypeRef bobReadyValue
= CFDictionaryGetValue(returnedValues
, sBobReady
);
88 if (isData(bobReadyValue
) && CFEqual(bobReadyValue
, nonce
)) {
89 SOSCloudKeychainClearAllSync();
92 dispatch_semaphore_signal(bob_ready_semaphore
);
94 pass("Ignoring change: %@", returnedValues
);
96 CFReleaseSafe(returnedValues
);
100 CloudKeychainReplyBlock reply_block
= ^ (CFDictionaryRef returnedValues
, CFErrorRef error
)
102 if (CFDictionaryGetCount(returnedValues
) != 0)
103 notification_block(returnedValues
);
107 SOSCloudKeychainClearAllSync();
109 CFArrayRef bobKey
= CFArrayCreateForCFTypes(kCFAllocatorDefault
, sBobReady
, NULL
);
110 SOSCloudKeychainRegisterKeysAndGet(bobKey
, global_queue
, reply_block
, notification_block
);
112 CFStringRef description
= SOSInterestListCopyDescription(bobKey
);
113 pass("%@", description
);
115 CFReleaseNull(description
);
116 CFReleaseNull(bobKey
);
118 CFDictionaryRef changes
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
, sAliceReady
, nonce
, NULL
);
119 SOSCloudKeychainPutObjectsInCloud(changes
, global_queue
, NULL
);
121 description
= SOSChangesCopyDescription(changes
, true);
122 pass("%@", description
);
123 CFReleaseNull(description
);
126 dispatch_semaphore_wait(bob_ready_semaphore
, DISPATCH_TIME_FOREVER
);
127 dispatch_release(bob_ready_semaphore
);
131 CFErrorRef error
= NULL
;
132 CFArrayRef no_keys
= CFArrayCreateForCFTypes(kCFAllocatorDefault
, NULL
);
133 SOSCloudKeychainUpdateKeys(false, no_keys
, no_keys
, no_keys
, &error
);
135 SOSCloudKeychainSetItemsChangedBlock(NULL
);
136 CFReleaseSafe(no_keys
);
137 CFReleaseSafe(error
);
140 CFReleaseNull(changes
);
143 static void WaitForSynchronization()
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
);
149 __block CFDataRef foundNonce
= NULL
;
150 CloudItemsChangedBlock notification_block
= ^ (CFDictionaryRef returnedValues
)
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
);
160 dispatch_semaphore_signal(alice_ready_semaphore
);
162 CFReleaseSafe(returnedValues
);
166 CloudKeychainReplyBlock reply_block
= ^ (CFDictionaryRef returnedValues
, CFErrorRef error
)
168 if (CFDictionaryGetCount(returnedValues
) != 0)
169 notification_block(returnedValues
);
172 CFArrayRef aliceKey
= CFArrayCreateForCFTypes(kCFAllocatorDefault
, sAliceReady
, NULL
);
173 SOSCloudKeychainRegisterKeysAndGet(aliceKey
, global_queue
, reply_block
, notification_block
);
175 CFStringRef description
= SOSInterestListCopyDescription(aliceKey
);
176 pass("%@", description
);
177 CFReleaseNull(description
);
180 dispatch_semaphore_wait(alice_ready_semaphore
, DISPATCH_TIME_FOREVER
);
181 dispatch_release(alice_ready_semaphore
);
184 CFDictionaryRef changes
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
, sBobReady
, foundNonce
, NULL
);
185 SOSCloudKeychainPutObjectsInCloud(changes
, global_queue
, NULL
);
186 CFReleaseSafe(changes
);
188 CFReleaseSafe(foundNonce
);
189 CFReleaseSafe(aliceKey
);
192 static CFStringRef circleKey
= CFSTR("Circle");
195 static SOSDataSourceRef
SetupTestFactory()
197 static SOSDataSourceRef our_data_source
;
199 our_data_source
= SOSTestDataSourceCreate();
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
;
207 return our_data_source
;
211 static void PurgeAndReload()
214 CFErrorRef error
= NULL
;
215 ok(SOSKeychainSaveAccountDataAndPurge(&error
), "Purged");
216 CFReleaseNull(error
);
218 ok(SOSKeychainAccountGetSharedAccount(), "Got Shared: %@", SOSKeychainAccountGetSharedAccount());
223 #define SOSKeychainAccountGetSharedAccount() NULL
226 #define kAliceTestCount 100
227 static void AliceTests()
229 plan_tests(kAliceTestCount
);
231 dispatch_semaphore_t notification_signal
= dispatch_semaphore_create(0);
233 notify_register_dispatch(kSOSCCCircleChangedNotification
, &token
,
234 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0),
236 dispatch_semaphore_signal(notification_signal
);
239 SOSCloudKeychainSetCallbackMethodXPC(); // call this first
240 ClearAndSynchronize();
243 SOSDataSourceRef our_test_data_source
= SetupTestFactory();
245 CFErrorRef error
= NULL
;
247 ok(SOSCCResetToOffering(&error
), "Reset: %@ [%@]", SOSKeychainAccountGetSharedAccount(), error
);
248 CFReleaseNull(error
);
252 CFArrayRef applicants
= NULL
;
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");
260 is(CFArrayGetCount(applicants
), 1, "Bob should be applying");
261 CFReleaseNull(error
);
263 ok(SOSCCAcceptApplicants(applicants
, &error
), "Accepted all applicants: %@", error
);
264 CFReleaseNull(error
);
265 CFReleaseSafe(applicants
);
270 pass("Waited long enough again");
273 CFDictionaryRef data
= SOSTestDataSourceGetDatabase(our_test_data_source
);
274 is(CFDictionaryGetCount(data
), 1, "Should have gotten bob's one");
278 #define kBobTestCount 100
279 static void BobTests()
281 plan_tests(kBobTestCount
);
283 dispatch_semaphore_t notification_signal
= dispatch_semaphore_create(0);
285 notify_register_dispatch(kSOSCCCircleChangedNotification
, &token
,
286 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT
, 0),
288 dispatch_semaphore_signal(notification_signal
);
291 SOSCloudKeychainSetCallbackMethodXPC(); // call this first
292 WaitForSynchronization();
295 SOSDataSourceRef our_test_data_source
= SetupTestFactory();
298 CFErrorRef error
= NULL
;
301 SOSObjectRef firstObject
= SOSDataSourceCreateGenericItem(our_test_data_source
, CFSTR("1234"), CFSTR("service"));
302 SOSTestDataSourceAddObject(our_test_data_source
, firstObject
, &error
);
305 CFReleaseNull(error
);
307 is(SOSCCThisDeviceIsInCircle(&error
), kSOSCCCircleAbsent
, "Shouldn't be a circle: %@", error
);
308 CFReleaseNull(error
);
312 CFArrayRef peers
= NULL
;
314 dispatch_semaphore_wait(notification_signal
, DISPATCH_TIME_FOREVER
);
315 peers
= SOSCCCopyPeerPeerInfo(&error
);
316 CFReleaseNull(error
);
317 } while (CFArrayGetCount(peers
) == 0);
319 pass("Peer arrived: %@", SOSKeychainAccountGetSharedAccount());
321 is(CFArrayGetCount(peers
), 1, "Only Alice should be there");
322 CFReleaseSafe(peers
);
324 ok(SOSCCRequestToJoinCircle(&error
), "Join circles: %@ [%@]", SOSKeychainAccountGetSharedAccount(), error
);
325 CFReleaseNull(error
);
330 dispatch_semaphore_wait(notification_signal
, DISPATCH_TIME_FOREVER
);
332 } while (SOSCCThisDeviceIsInCircle(&error
) != kSOSCCInCircle
);
333 pass("Was admitted: %@ [%@]", SOSKeychainAccountGetSharedAccount(), error
);
334 CFReleaseNull(error
);
336 is(SOSCCThisDeviceIsInCircle(&error
), kSOSCCInCircle
, "Should be in circle: %@", error
);
337 CFReleaseNull(error
);
343 pass("Waited long enough again: %@", SOSKeychainAccountGetSharedAccount());
346 CFDictionaryRef data
= SOSTestDataSourceGetDatabase(our_test_data_source
);
347 is(CFDictionaryGetCount(data
), 1, "Only have one");
352 static const struct option options
[] =
354 { "identity", optional_argument
, NULL
, 'i' },
359 int sc_120_cloudcircle(int argc
, char *const *argv
)
361 char *identity
= NULL
;
365 bool isAlice
= false;
367 while (argSlot
= -1, (arg
= getopt_long(argc
, (char * const *)argv
, "i:vC", options
, &argSlot
)) != -1)
371 identity
= (char *)(optarg
);
374 fail("arg: %s", optarg
);
380 if (!strcmp(identity
, "alice"))