2 * Copyright (c) 2013-2016 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
33 #include <Security/SecBase.h>
34 #include <Security/SecItem.h>
36 #include <CoreFoundation/CFDictionary.h>
38 #include <Security/SecureObjectSync/SOSAccount.h>
39 #include <Security/SecureObjectSync/SOSCloudCircle.h>
40 #include <Security/SecureObjectSync/SOSInternal.h>
41 #include <Security/SecureObjectSync/SOSUserKeygen.h>
42 #include <Security/SecureObjectSync/SOSTransport.h>
43 #include <Security/SecureObjectSync/SOSEnginePriv.h>
44 #include "SOSCloudKeychainLogging.h"
49 #include "secd_regressions.h"
50 #include "SOSTestDataSource.h"
51 #include "SOSTestDevice.h"
53 #include "SOSRegressionUtilities.h"
54 #include <utilities/SecCFWrappers.h>
55 #include <Security/SecKeyPriv.h>
57 #include <securityd/SOSCloudCircleServer.h>
59 #include "SOSAccountTesting.h"
61 #include "SecdTestKeychainUtilities.h"
63 static int kTestTestCount
= 182;
65 static void TestSOSEngineDoOnQueue(SOSEngineRef engine
, dispatch_block_t action
)
67 dispatch_sync(engine
->queue
, action
);
70 static bool SOSAccountIsThisPeerIDMe(SOSAccountRef account
, CFStringRef peerID
) {
71 SOSPeerInfoRef mypi
= SOSFullPeerInfoGetPeerInfo(account
->my_identity
);
72 CFStringRef myPeerID
= SOSPeerInfoGetPeerID(mypi
);
74 return myPeerID
&& CFEqualSafe(myPeerID
, peerID
);
77 static bool TestSOSEngineDoTxnOnQueue(SOSEngineRef engine
, CFErrorRef
*error
, void(^transaction
)(SOSTransactionRef txn
, bool *commit
))
79 return SOSDataSourceWithCommitQueue(engine
->dataSource
, error
, ^(SOSTransactionRef txn
, bool *commit
) {
80 TestSOSEngineDoOnQueue(engine
, ^{ transaction(txn
, commit
); });
84 static void compareCoders(CFMutableDictionaryRef beforeCoders
, CFMutableDictionaryRef afterCoderState
)
86 CFDictionaryForEach(beforeCoders
, ^(const void *key
, const void *value
) {
87 CFStringRef beforePeerid
= (CFStringRef
)key
;
88 SOSCoderRef beforeCoderData
= (SOSCoderRef
)value
;
89 SOSCoderRef afterCoderData
= (SOSCoderRef
)CFDictionaryGetValue(afterCoderState
, beforePeerid
);
90 ok(CFEqual(beforeCoderData
,afterCoderData
));
94 static void ids_test_sync(SOSAccountRef alice_account
, SOSAccountRef bob_account
){
96 CFMutableDictionaryRef changes
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
97 __block
bool SyncingCompletedOverIDS
= false;
98 __block CFErrorRef localError
= NULL
;
99 __block
bool done
= false;
101 SOSCircleForEachValidPeer(alice_account
->trusted_circle
, alice_account
->user_public
, ^(SOSPeerInfoRef peer
) {
102 if (!SOSAccountIsThisPeerIDMe(alice_account
, SOSPeerInfoGetPeerID(peer
))) {
103 if(SOSPeerInfoShouldUseIDSTransport(SOSFullPeerInfoGetPeerInfo(alice_account
->my_identity
), peer
) &&
104 SOSPeerInfoShouldUseIDSMessageFragmentation(SOSFullPeerInfoGetPeerInfo(alice_account
->my_identity
), peer
)){
105 secnotice("IDS Transport","Syncing with IDS capable peers using IDS!");
107 CFMutableDictionaryRef circleToIdsId
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
108 CFMutableArrayRef ids
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
109 CFArrayAppendValue(ids
, SOSPeerInfoGetPeerID(peer
));
110 CFDictionaryAddValue(circleToIdsId
, SOSCircleGetName(alice_account
->trusted_circle
), ids
);
111 SOSEngineRef alice_engine
= SOSTransportMessageGetEngine(alice_account
->ids_message_transport
);
113 //testing loading and saving coders
114 ok(alice_engine
->coders
);
115 CFMutableDictionaryRef beforeCoders
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, CFDictionaryGetCount(alice_engine
->coders
), alice_engine
->coders
);
116 TestSOSEngineDoTxnOnQueue(alice_engine
, &localError
, ^(SOSTransactionRef txn
, bool *commit
) {
117 ok(TestSOSEngineLoadCoders(SOSTransportMessageGetEngine(alice_account
->ids_message_transport
), txn
, &localError
));
120 ok(alice_engine
->coders
);
122 TestSOSEngineDoTxnOnQueue(alice_engine
, &localError
, ^(SOSTransactionRef txn
, bool *commit
) {
123 ok(SOSTestEngineSaveCoders(alice_engine
, txn
, &localError
));
126 compareCoders(beforeCoders
, alice_engine
->coders
);
128 //syncing with all peers
129 SyncingCompletedOverIDS
= SOSTransportMessageSyncWithPeers(alice_account
->ids_message_transport
, circleToIdsId
, &localError
);
131 //testing load after sync with all peers
132 CFMutableDictionaryRef codersAfterSyncBeforeLoad
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, CFDictionaryGetCount(alice_engine
->coders
), alice_engine
->coders
);
133 TestSOSEngineDoTxnOnQueue(alice_engine
, &localError
, ^(SOSTransactionRef txn
, bool *commit
) {
134 ok(TestSOSEngineLoadCoders(SOSTransportMessageGetEngine(alice_account
->ids_message_transport
), txn
, &localError
));
136 compareCoders(codersAfterSyncBeforeLoad
, alice_engine
->coders
);
138 CFReleaseNull(codersAfterSyncBeforeLoad
);
139 CFReleaseNull(beforeCoders
);
140 CFReleaseNull(circleToIdsId
);
146 ProcessChangesUntilNoChange(changes
, alice_account
, bob_account
, NULL
);
148 SOSCircleForEachValidPeer(bob_account
->trusted_circle
, bob_account
->user_public
, ^(SOSPeerInfoRef peer
) {
149 if (!SOSAccountIsThisPeerIDMe(bob_account
, SOSPeerInfoGetPeerID(peer
))) {
150 if(SOSPeerInfoShouldUseIDSTransport(SOSFullPeerInfoGetPeerInfo(bob_account
->my_identity
), peer
) &&
151 SOSPeerInfoShouldUseIDSMessageFragmentation(SOSFullPeerInfoGetPeerInfo(bob_account
->my_identity
), peer
)){
152 secnotice("IDS Transport","Syncing with IDS capable peers using IDS!");
154 CFMutableDictionaryRef circleToIdsId
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
155 CFMutableArrayRef ids
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
156 CFArrayAppendValue(ids
, SOSPeerInfoGetPeerID(peer
));
157 CFDictionaryAddValue(circleToIdsId
, SOSCircleGetName(bob_account
->trusted_circle
), ids
);
158 SOSEngineRef bob_engine
= SOSTransportMessageGetEngine(bob_account
->ids_message_transport
);
160 //testing loading and saving coders
161 ok(bob_engine
->coders
);
162 CFMutableDictionaryRef beforeCoders
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, CFDictionaryGetCount(bob_engine
->coders
), bob_engine
->coders
);
163 TestSOSEngineDoTxnOnQueue(bob_engine
, &localError
, ^(SOSTransactionRef txn
, bool *commit
) {
164 ok(TestSOSEngineLoadCoders(SOSTransportMessageGetEngine(bob_account
->ids_message_transport
), txn
, &localError
));
167 ok(bob_engine
->coders
);
169 TestSOSEngineDoTxnOnQueue(bob_engine
, &localError
, ^(SOSTransactionRef txn
, bool *commit
) {
170 ok(SOSTestEngineSaveCoders(bob_engine
, txn
, &localError
));
173 compareCoders(beforeCoders
, bob_engine
->coders
);
175 SyncingCompletedOverIDS
&= SOSTransportMessageSyncWithPeers(bob_account
->ids_message_transport
, circleToIdsId
, &localError
);
177 //testing load after sync with all peers
178 CFMutableDictionaryRef codersAfterSyncBeforeLoad
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, CFDictionaryGetCount(bob_engine
->coders
), bob_engine
->coders
);
179 TestSOSEngineDoTxnOnQueue(bob_engine
, &localError
, ^(SOSTransactionRef txn
, bool *commit
) {
180 ok(TestSOSEngineLoadCoders(SOSTransportMessageGetEngine(bob_account
->ids_message_transport
), txn
, &localError
));
182 compareCoders(codersAfterSyncBeforeLoad
, bob_engine
->coders
);
183 CFReleaseNull(codersAfterSyncBeforeLoad
);
184 CFReleaseNull(beforeCoders
);
185 CFReleaseNull(circleToIdsId
);
191 if(CFDictionaryGetCount(SOSTransportMessageIDSTestGetChanges(alice_account
->ids_message_transport
)) == 0 && CFDictionaryGetCount(SOSTransportMessageIDSTestGetChanges(bob_account
->ids_message_transport
)) == 0){
196 ProcessChangesUntilNoChange(changes
, alice_account
, bob_account
, NULL
);
198 }while(done
== false);
199 CFReleaseNull(changes
);
201 ok(SyncingCompletedOverIDS
, "synced items over IDS");
205 static void tests(void)
208 __block CFErrorRef error
= NULL
;
209 CFDataRef cfpassword
= CFDataCreate(NULL
, (uint8_t *) "FooFooFoo", 10);
210 CFDataRef cfwrong_password
= CFDataCreate(NULL
, (uint8_t *) "NotFooFooFoo", 10);
211 CFStringRef cfaccount
= CFSTR("test@test.org");
213 CFMutableDictionaryRef changes
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
214 SOSAccountRef alice_account
= CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource"));
215 SOSAccountRef bob_account
= CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource"));
217 ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account
, cfaccount
, cfpassword
, &error
), "Credential setting (%@)", error
);
219 // Bob wins writing at this point, feed the changes back to alice.
220 is(ProcessChangesUntilNoChange(changes
, alice_account
, bob_account
, NULL
), 1, "updates");
222 ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account
, cfaccount
, cfpassword
, &error
), "Credential setting (%@)", error
);
223 CFReleaseNull(error
);
224 ok(SOSAccountTryUserCredentials(alice_account
, cfaccount
, cfpassword
, &error
), "Credential trying (%@)", error
);
225 CFReleaseNull(error
);
226 ok(!SOSAccountTryUserCredentials(alice_account
, cfaccount
, cfwrong_password
, &error
), "Credential failing (%@)", error
);
227 CFReleaseNull(cfwrong_password
);
228 is(error
? CFErrorGetCode(error
) : 0, kSOSErrorWrongPassword
, "Expected SOSErrorWrongPassword");
229 CFReleaseNull(error
);
231 ok(SOSAccountResetToOffering_wTxn(alice_account
, &error
), "Reset to offering (%@)", error
);
232 CFReleaseNull(error
);
234 is(ProcessChangesUntilNoChange(changes
, alice_account
, bob_account
, NULL
), 2, "updates");
236 ok(SOSAccountHasCompletedInitialSync(alice_account
), "Alice thinks she's completed initial sync");
238 ok(SOSAccountJoinCircles_wTxn(bob_account
, &error
), "Bob Applies (%@)", error
);
239 CFReleaseNull(error
);
241 is(ProcessChangesUntilNoChange(changes
, alice_account
, bob_account
, NULL
), 2, "updates");
244 CFArrayRef applicants
= SOSAccountCopyApplicants(alice_account
, &error
);
246 ok(applicants
&& CFArrayGetCount(applicants
) == 1, "See one applicant %@ (%@)", applicants
, error
);
247 ok(SOSAccountAcceptApplicants(alice_account
, applicants
, &error
), "Alice accepts (%@)", error
);
248 CFReleaseNull(error
);
249 CFReleaseNull(applicants
);
252 is(ProcessChangesUntilNoChange(changes
, alice_account
, bob_account
, NULL
), 3, "updates");
254 accounts_agree("bob&alice pair", bob_account
, alice_account
);
256 CFArrayRef peers
= SOSAccountCopyPeers(alice_account
, &error
);
257 ok(peers
&& CFArrayGetCount(peers
) == 2, "See two peers %@ (%@)", peers
, error
);
258 CFReleaseNull(peers
);
260 //creating test devices
263 // Optionally prefix each peer with name to make them more unique.
264 CFArrayRef deviceIDs
= CFArrayCreateForCFTypes(kCFAllocatorDefault
,SOSAccountGetMyPeerID(alice_account
), SOSAccountGetMyPeerID(bob_account
), NULL
);
265 CFSetRef views
= SOSViewsCopyTestV2Default();
266 CFMutableArrayRef peerMetas
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
267 CFStringRef deviceID
;
268 CFArrayForEachC(deviceIDs
, deviceID
) {
269 SOSPeerMetaRef peerMeta
= SOSPeerMetaCreateWithComponents(deviceID
, views
, NULL
);
270 CFArrayAppendValue(peerMetas
, peerMeta
);
271 CFReleaseNull(peerMeta
);
274 CFReleaseNull(views
);
275 CFArrayForEachC(deviceIDs
, deviceID
) {
276 SOSTestDeviceRef device
= SOSTestDeviceCreateWithDbNamed(kCFAllocatorDefault
, deviceID
, deviceID
);
277 SOSTestDeviceSetPeerIDs(device
, peerMetas
, version
, NULL
);
279 if(CFEqualSafe(deviceID
, SOSAccountGetMyPeerID(alice_account
))){
280 alice_account
->factory
= device
->dsf
;
281 SOSTestDeviceAddGenericItem(device
, CFSTR("Alice"), CFSTR("Alice-add"));
284 bob_account
->factory
= device
->dsf
;
285 SOSTestDeviceAddGenericItem(device
, CFSTR("Bob"), CFSTR("Bob-add"));
288 CFReleaseNull(device
);
290 CFReleaseNull(deviceIDs
);
291 CFReleaseNull(peerMetas
);
293 SOSUnregisterAllTransportMessages();
294 CFArrayRemoveAllValues(message_transports
);
296 alice_account
->ids_message_transport
= (SOSTransportMessageRef
)SOSTransportMessageIDSTestCreate(alice_account
, CFSTR("Alice"), CFSTR("TestSource"), &error
);
297 bob_account
->ids_message_transport
= (SOSTransportMessageRef
)SOSTransportMessageIDSTestCreate(bob_account
, CFSTR("Bob"), CFSTR("TestSource"), &error
);
299 bool result
= SOSAccountModifyCircle(alice_account
, &error
, ^bool(SOSCircleRef circle
) {
300 CFErrorRef localError
= NULL
;
302 SOSFullPeerInfoUpdateTransportType(alice_account
->my_identity
, SOSTransportMessageTypeIDSV2
, &localError
);
303 SOSFullPeerInfoUpdateTransportPreference(alice_account
->my_identity
, kCFBooleanFalse
, &localError
);
304 SOSFullPeerInfoUpdateTransportFragmentationPreference(alice_account
->my_identity
, kCFBooleanTrue
, &localError
);
306 return SOSCircleHasPeer(circle
, SOSFullPeerInfoGetPeerInfo(alice_account
->my_identity
), NULL
);
309 ok(result
, "Alice account update circle with transport type");
311 is(ProcessChangesUntilNoChange(changes
, alice_account
, bob_account
, NULL
), 2, "updates");
313 result
= SOSAccountModifyCircle(bob_account
, &error
, ^bool(SOSCircleRef circle
) {
314 CFErrorRef localError
= NULL
;
316 SOSFullPeerInfoUpdateTransportType(bob_account
->my_identity
, SOSTransportMessageTypeIDSV2
, &localError
);
317 SOSFullPeerInfoUpdateTransportPreference(bob_account
->my_identity
, kCFBooleanFalse
, &localError
);
318 SOSFullPeerInfoUpdateTransportFragmentationPreference(bob_account
->my_identity
, kCFBooleanTrue
, &localError
);
320 return SOSCircleHasPeer(circle
, SOSFullPeerInfoGetPeerInfo(bob_account
->my_identity
), NULL
);
323 ok(result
, "Bob account update circle with transport type");
324 is(ProcessChangesUntilNoChange(changes
, alice_account
, bob_account
, NULL
), 2, "updates");
326 CFStringRef alice_transportType
=SOSPeerInfoCopyTransportType(SOSAccountGetMyPeerInfo(alice_account
));
327 CFStringRef bob_accountTransportType
= SOSPeerInfoCopyTransportType(SOSAccountGetMyPeerInfo(bob_account
));
328 ok(CFEqualSafe(alice_transportType
, CFSTR("IDS2.0")), "Alice transport type not IDS");
329 ok(CFEqualSafe(bob_accountTransportType
, CFSTR("IDS2.0")), "Bob transport type not IDS");
331 CFReleaseNull(alice_transportType
);
332 CFReleaseNull(bob_accountTransportType
);
334 SOSTransportMessageIDSTestSetName(alice_account
->ids_message_transport
, CFSTR("Alice Account"));
335 ok(SOSTransportMessageIDSTestGetName(alice_account
->ids_message_transport
) != NULL
, "retrieved getting account name");
336 ok(SOSAccountRetrieveDeviceIDFromIDSKeychainSyncingProxy(alice_account
, &error
) != false, "device ID from IDSKeychainSyncingProxy");
338 SOSTransportMessageIDSTestSetName(bob_account
->ids_message_transport
, CFSTR("Bob Account"));
339 ok(SOSTransportMessageIDSTestGetName(bob_account
->ids_message_transport
) != NULL
, "retrieved getting account name");
340 ok(SOSAccountRetrieveDeviceIDFromIDSKeychainSyncingProxy(bob_account
, &error
) != false, "device ID from IDSKeychainSyncingProxy");
343 ok(SOSAccountSetMyDSID(alice_account
, CFSTR("Alice"),&error
), "Setting IDS device ID");
344 CFStringRef alice_dsid
= SOSAccountCopyDeviceID(alice_account
, &error
);
345 ok(CFEqualSafe(alice_dsid
, CFSTR("Alice")), "Getting IDS device ID");
347 ok(SOSAccountSetMyDSID(bob_account
, CFSTR("Bob"),&error
), "Setting IDS device ID");
348 CFStringRef bob_dsid
= SOSAccountCopyDeviceID(bob_account
, &error
);
349 ok(CFEqualSafe(bob_dsid
, CFSTR("Bob")), "Getting IDS device ID");
351 is(ProcessChangesUntilNoChange(changes
, alice_account
, bob_account
, NULL
), 3, "updates");
353 ok(SOSAccountEnsurePeerRegistration(alice_account
, NULL
), "ensure peer registration - alice");
354 ok(SOSAccountEnsurePeerRegistration(bob_account
, NULL
), "ensure peer registration - bob");
356 ids_test_sync(alice_account
, bob_account
);
358 SOSUnregisterAllTransportMessages();
359 SOSUnregisterAllTransportCircles();
360 SOSUnregisterAllTransportKeyParameters();
361 CFArrayRemoveAllValues(key_transports
);
362 CFArrayRemoveAllValues(circle_transports
);
363 CFArrayRemoveAllValues(message_transports
);
364 CFReleaseNull(alice_account
);
365 CFReleaseNull(bob_account
);
369 int secd_201_coders(int argc
, char *const *argv
)
371 plan_tests(kTestTestCount
);
373 secd_test_setup_temp_keychain(__FUNCTION__
, NULL
);