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>
48 #include "secd_regressions.h"
49 #include "SOSTestDataSource.h"
50 #include "SOSTestDevice.h"
52 #include "SOSRegressionUtilities.h"
53 #include <utilities/SecCFWrappers.h>
54 #include <Security/SecKeyPriv.h>
56 #include <securityd/SOSCloudCircleServer.h>
58 #include "SOSAccountTesting.h"
60 #include "SecdTestKeychainUtilities.h"
62 static int kTestTestCount
= 124;
64 static void TestSOSEngineDoOnQueue(SOSEngineRef engine
, dispatch_block_t action
)
66 dispatch_sync(engine
->queue
, action
);
69 static bool SOSAccountIsThisPeerIDMe(SOSAccountRef account
, CFStringRef peerID
) {
70 SOSPeerInfoRef mypi
= SOSFullPeerInfoGetPeerInfo(account
->my_identity
);
71 CFStringRef myPeerID
= SOSPeerInfoGetPeerID(mypi
);
73 return myPeerID
&& CFEqualSafe(myPeerID
, peerID
);
76 static bool TestSOSEngineDoTxnOnQueue(SOSEngineRef engine
, CFErrorRef
*error
, void(^transaction
)(SOSTransactionRef txn
, bool *commit
))
78 return SOSDataSourceWithCommitQueue(engine
->dataSource
, error
, ^(SOSTransactionRef txn
, bool *commit
) {
79 TestSOSEngineDoOnQueue(engine
, ^{ transaction(txn
, commit
); });
83 static void compareCoders(CFMutableDictionaryRef beforeCoders
, CFMutableDictionaryRef afterCoderState
)
85 CFDictionaryForEach(beforeCoders
, ^(const void *key
, const void *value
) {
86 CFStringRef beforePeerid
= (CFStringRef
)key
;
87 SOSCoderRef beforeCoderData
= (SOSCoderRef
)value
;
88 SOSCoderRef afterCoderData
= (SOSCoderRef
)CFDictionaryGetValue(afterCoderState
, beforePeerid
);
89 ok(CFEqual(beforeCoderData
,afterCoderData
));
93 static void ids_test_sync(SOSAccountRef alice_account
, SOSAccountRef bob_account
){
95 CFMutableDictionaryRef changes
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
96 __block
bool SyncingCompletedOverIDS
= false;
97 __block CFErrorRef localError
= NULL
;
98 __block
bool done
= false;
100 SOSCircleForEachValidPeer(alice_account
->trusted_circle
, alice_account
->user_public
, ^(SOSPeerInfoRef peer
) {
101 if (!SOSAccountIsThisPeerIDMe(alice_account
, SOSPeerInfoGetPeerID(peer
))) {
102 if(SOSPeerInfoShouldUseIDSTransport(SOSFullPeerInfoGetPeerInfo(alice_account
->my_identity
), peer
) &&
103 SOSPeerInfoShouldUseIDSMessageFragmentation(SOSFullPeerInfoGetPeerInfo(alice_account
->my_identity
), peer
)){
104 secnotice("IDS Transport","Syncing with IDS capable peers using IDS!");
106 CFMutableSetRef ids
= CFSetCreateMutableForCFTypes(kCFAllocatorDefault
);
107 CFSetAddValue(ids
, SOSPeerInfoGetPeerID(peer
));
109 SOSEngineRef alice_engine
= SOSTransportMessageGetEngine(alice_account
->ids_message_transport
);
111 //testing loading and saving coders
112 ok(alice_engine
->coders
);
113 CFMutableDictionaryRef beforeCoders
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, CFDictionaryGetCount(alice_engine
->coders
), alice_engine
->coders
);
114 TestSOSEngineDoTxnOnQueue(alice_engine
, &localError
, ^(SOSTransactionRef txn
, bool *commit
) {
115 ok(TestSOSEngineLoadCoders(SOSTransportMessageGetEngine(alice_account
->ids_message_transport
), txn
, &localError
));
118 ok(alice_engine
->coders
);
120 TestSOSEngineDoTxnOnQueue(alice_engine
, &localError
, ^(SOSTransactionRef txn
, bool *commit
) {
121 ok(SOSTestEngineSaveCoders(alice_engine
, txn
, &localError
));
124 compareCoders(beforeCoders
, alice_engine
->coders
);
126 //syncing with all peers
127 SyncingCompletedOverIDS
= SOSTransportMessageSyncWithPeers(alice_account
->ids_message_transport
, ids
, &localError
);
129 //testing load after sync with all peers
130 CFMutableDictionaryRef codersAfterSyncBeforeLoad
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, CFDictionaryGetCount(alice_engine
->coders
), alice_engine
->coders
);
131 TestSOSEngineDoTxnOnQueue(alice_engine
, &localError
, ^(SOSTransactionRef txn
, bool *commit
) {
132 ok(TestSOSEngineLoadCoders(SOSTransportMessageGetEngine(alice_account
->ids_message_transport
), txn
, &localError
));
134 compareCoders(codersAfterSyncBeforeLoad
, alice_engine
->coders
);
136 CFReleaseNull(codersAfterSyncBeforeLoad
);
137 CFReleaseNull(beforeCoders
);
143 ProcessChangesUntilNoChange(changes
, alice_account
, bob_account
, NULL
);
145 SOSCircleForEachValidPeer(bob_account
->trusted_circle
, bob_account
->user_public
, ^(SOSPeerInfoRef peer
) {
146 if (!SOSAccountIsThisPeerIDMe(bob_account
, SOSPeerInfoGetPeerID(peer
))) {
147 if(SOSPeerInfoShouldUseIDSTransport(SOSFullPeerInfoGetPeerInfo(bob_account
->my_identity
), peer
) &&
148 SOSPeerInfoShouldUseIDSMessageFragmentation(SOSFullPeerInfoGetPeerInfo(bob_account
->my_identity
), peer
)){
149 secnotice("IDS Transport","Syncing with IDS capable peers using IDS!");
151 CFMutableSetRef ids
= CFSetCreateMutableForCFTypes(kCFAllocatorDefault
);
152 CFSetAddValue(ids
, SOSPeerInfoGetPeerID(peer
));
154 SOSEngineRef bob_engine
= SOSTransportMessageGetEngine(bob_account
->ids_message_transport
);
156 //testing loading and saving coders
157 ok(bob_engine
->coders
);
158 CFMutableDictionaryRef beforeCoders
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, CFDictionaryGetCount(bob_engine
->coders
), bob_engine
->coders
);
159 TestSOSEngineDoTxnOnQueue(bob_engine
, &localError
, ^(SOSTransactionRef txn
, bool *commit
) {
160 ok(TestSOSEngineLoadCoders(SOSTransportMessageGetEngine(bob_account
->ids_message_transport
), txn
, &localError
));
163 ok(bob_engine
->coders
);
165 TestSOSEngineDoTxnOnQueue(bob_engine
, &localError
, ^(SOSTransactionRef txn
, bool *commit
) {
166 ok(SOSTestEngineSaveCoders(bob_engine
, txn
, &localError
));
169 compareCoders(beforeCoders
, bob_engine
->coders
);
171 SyncingCompletedOverIDS
&= SOSTransportMessageSyncWithPeers(bob_account
->ids_message_transport
, ids
, &localError
);
173 //testing load after sync with all peers
174 CFMutableDictionaryRef codersAfterSyncBeforeLoad
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, CFDictionaryGetCount(bob_engine
->coders
), bob_engine
->coders
);
175 TestSOSEngineDoTxnOnQueue(bob_engine
, &localError
, ^(SOSTransactionRef txn
, bool *commit
) {
176 ok(TestSOSEngineLoadCoders(SOSTransportMessageGetEngine(bob_account
->ids_message_transport
), txn
, &localError
));
178 compareCoders(codersAfterSyncBeforeLoad
, bob_engine
->coders
);
179 CFReleaseNull(codersAfterSyncBeforeLoad
);
180 CFReleaseNull(beforeCoders
);
186 if(CFDictionaryGetCount(SOSTransportMessageIDSTestGetChanges(alice_account
->ids_message_transport
)) == 0 && CFDictionaryGetCount(SOSTransportMessageIDSTestGetChanges(bob_account
->ids_message_transport
)) == 0){
191 ProcessChangesUntilNoChange(changes
, alice_account
, bob_account
, NULL
);
193 }while(done
== false);
194 CFReleaseNull(changes
);
196 ok(SyncingCompletedOverIDS
, "synced items over IDS");
200 static void tests(void)
203 __block CFErrorRef error
= NULL
;
204 CFDataRef cfpassword
= CFDataCreate(NULL
, (uint8_t *) "FooFooFoo", 10);
205 CFDataRef cfwrong_password
= CFDataCreate(NULL
, (uint8_t *) "NotFooFooFoo", 10);
206 CFStringRef cfaccount
= CFSTR("test@test.org");
208 CFMutableDictionaryRef changes
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
209 SOSAccountRef alice_account
= CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource"));
210 SOSAccountRef bob_account
= CreateAccountForLocalChanges(CFSTR("Bob"), CFSTR("TestSource"));
212 ok(SOSAccountAssertUserCredentialsAndUpdate(bob_account
, cfaccount
, cfpassword
, &error
), "Credential setting (%@)", error
);
214 // Bob wins writing at this point, feed the changes back to alice.
215 is(ProcessChangesUntilNoChange(changes
, alice_account
, bob_account
, NULL
), 1, "updates");
217 ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account
, cfaccount
, cfpassword
, &error
), "Credential setting (%@)", error
);
218 CFReleaseNull(error
);
219 ok(SOSAccountTryUserCredentials(alice_account
, cfaccount
, cfpassword
, &error
), "Credential trying (%@)", error
);
220 CFReleaseNull(error
);
221 ok(!SOSAccountTryUserCredentials(alice_account
, cfaccount
, cfwrong_password
, &error
), "Credential failing (%@)", error
);
222 CFReleaseNull(cfwrong_password
);
223 is(error
? CFErrorGetCode(error
) : 0, kSOSErrorWrongPassword
, "Expected SOSErrorWrongPassword");
224 CFReleaseNull(error
);
226 ok(SOSAccountResetToOffering_wTxn(alice_account
, &error
), "Reset to offering (%@)", error
);
227 CFReleaseNull(error
);
229 is(ProcessChangesUntilNoChange(changes
, alice_account
, bob_account
, NULL
), 2, "updates");
231 ok(SOSAccountHasCompletedInitialSync(alice_account
), "Alice thinks she's completed initial sync");
233 ok(SOSAccountJoinCircles_wTxn(bob_account
, &error
), "Bob Applies (%@)", error
);
234 CFReleaseNull(error
);
236 is(ProcessChangesUntilNoChange(changes
, alice_account
, bob_account
, NULL
), 2, "updates");
239 CFArrayRef applicants
= SOSAccountCopyApplicants(alice_account
, &error
);
241 ok(applicants
&& CFArrayGetCount(applicants
) == 1, "See one applicant %@ (%@)", applicants
, error
);
242 ok(SOSAccountAcceptApplicants(alice_account
, applicants
, &error
), "Alice accepts (%@)", error
);
243 CFReleaseNull(error
);
244 CFReleaseNull(applicants
);
247 is(ProcessChangesUntilNoChange(changes
, alice_account
, bob_account
, NULL
), 3, "updates");
249 accounts_agree("bob&alice pair", bob_account
, alice_account
);
251 CFArrayRef peers
= SOSAccountCopyPeers(alice_account
, &error
);
252 ok(peers
&& CFArrayGetCount(peers
) == 2, "See two peers %@ (%@)", peers
, error
);
253 CFReleaseNull(peers
);
255 //creating test devices
258 // Optionally prefix each peer with name to make them more unique.
259 CFArrayRef deviceIDs
= CFArrayCreateForCFTypes(kCFAllocatorDefault
,SOSAccountGetMyPeerID(alice_account
), SOSAccountGetMyPeerID(bob_account
), NULL
);
260 CFSetRef views
= SOSViewsCopyTestV2Default();
261 CFMutableArrayRef peerMetas
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
262 CFStringRef deviceID
;
263 CFArrayForEachC(deviceIDs
, deviceID
) {
264 SOSPeerMetaRef peerMeta
= SOSPeerMetaCreateWithComponents(deviceID
, views
, NULL
);
265 CFArrayAppendValue(peerMetas
, peerMeta
);
266 CFReleaseNull(peerMeta
);
269 CFReleaseNull(views
);
270 CFArrayForEachC(deviceIDs
, deviceID
) {
271 SOSTestDeviceRef device
= SOSTestDeviceCreateWithDbNamed(kCFAllocatorDefault
, deviceID
, deviceID
);
272 SOSTestDeviceSetPeerIDs(device
, peerMetas
, version
, NULL
);
274 if(CFEqualSafe(deviceID
, SOSAccountGetMyPeerID(alice_account
))){
275 alice_account
->factory
= device
->dsf
;
276 SOSTestDeviceAddGenericItem(device
, CFSTR("Alice"), CFSTR("Alice-add"));
279 bob_account
->factory
= device
->dsf
;
280 SOSTestDeviceAddGenericItem(device
, CFSTR("Bob"), CFSTR("Bob-add"));
283 CFReleaseNull(device
);
285 CFReleaseNull(deviceIDs
);
286 CFReleaseNull(peerMetas
);
288 SOSUnregisterAllTransportMessages();
289 CFArrayRemoveAllValues(message_transports
);
291 alice_account
->ids_message_transport
= (SOSTransportMessageRef
)SOSTransportMessageIDSTestCreate(alice_account
, CFSTR("Alice"), CFSTR("TestSource"), &error
);
292 bob_account
->ids_message_transport
= (SOSTransportMessageRef
)SOSTransportMessageIDSTestCreate(bob_account
, CFSTR("Bob"), CFSTR("TestSource"), &error
);
294 bool result
= SOSAccountModifyCircle(alice_account
, &error
, ^bool(SOSCircleRef circle
) {
295 CFErrorRef localError
= NULL
;
297 SOSFullPeerInfoUpdateTransportType(alice_account
->my_identity
, SOSTransportMessageTypeIDSV2
, &localError
);
298 SOSFullPeerInfoUpdateTransportPreference(alice_account
->my_identity
, kCFBooleanFalse
, &localError
);
299 SOSFullPeerInfoUpdateTransportFragmentationPreference(alice_account
->my_identity
, kCFBooleanTrue
, &localError
);
300 SOSFullPeerInfoUpdateTransportAckModelPreference(alice_account
->my_identity
, kCFBooleanTrue
, &localError
);
302 return SOSCircleHasPeer(circle
, SOSFullPeerInfoGetPeerInfo(alice_account
->my_identity
), NULL
);
305 ok(result
, "Alice account update circle with transport type");
307 is(ProcessChangesUntilNoChange(changes
, alice_account
, bob_account
, NULL
), 2, "updates");
309 result
= SOSAccountModifyCircle(bob_account
, &error
, ^bool(SOSCircleRef circle
) {
310 CFErrorRef localError
= NULL
;
312 SOSFullPeerInfoUpdateTransportType(bob_account
->my_identity
, SOSTransportMessageTypeIDSV2
, &localError
);
313 SOSFullPeerInfoUpdateTransportPreference(bob_account
->my_identity
, kCFBooleanFalse
, &localError
);
314 SOSFullPeerInfoUpdateTransportFragmentationPreference(bob_account
->my_identity
, kCFBooleanTrue
, &localError
);
315 SOSFullPeerInfoUpdateTransportAckModelPreference(bob_account
->my_identity
, kCFBooleanTrue
, &localError
);
317 return SOSCircleHasPeer(circle
, SOSFullPeerInfoGetPeerInfo(bob_account
->my_identity
), NULL
);
320 ok(result
, "Bob account update circle with transport type");
321 is(ProcessChangesUntilNoChange(changes
, alice_account
, bob_account
, NULL
), 2, "updates");
323 CFStringRef alice_transportType
=SOSPeerInfoCopyTransportType(SOSAccountGetMyPeerInfo(alice_account
));
324 CFStringRef bob_accountTransportType
= SOSPeerInfoCopyTransportType(SOSAccountGetMyPeerInfo(bob_account
));
325 ok(CFEqualSafe(alice_transportType
, CFSTR("IDS2.0")), "Alice transport type not IDS");
326 ok(CFEqualSafe(bob_accountTransportType
, CFSTR("IDS2.0")), "Bob transport type not IDS");
328 CFReleaseNull(alice_transportType
);
329 CFReleaseNull(bob_accountTransportType
);
331 SOSTransportMessageIDSTestSetName(alice_account
->ids_message_transport
, CFSTR("Alice Account"));
332 ok(SOSTransportMessageIDSTestGetName(alice_account
->ids_message_transport
) != NULL
, "retrieved getting account name");
333 ok(SOSAccountRetrieveDeviceIDFromKeychainSyncingOverIDSProxy(alice_account
, &error
) != false, "device ID from KeychainSyncingOverIDSProxy");
335 SOSTransportMessageIDSTestSetName(bob_account
->ids_message_transport
, CFSTR("Bob Account"));
336 ok(SOSTransportMessageIDSTestGetName(bob_account
->ids_message_transport
) != NULL
, "retrieved getting account name");
337 ok(SOSAccountRetrieveDeviceIDFromKeychainSyncingOverIDSProxy(bob_account
, &error
) != false, "device ID from KeychainSyncingOverIDSProxy");
340 ok(SOSAccountSetMyDSID_wTxn(alice_account
, CFSTR("Alice"),&error
), "Setting IDS device ID");
341 CFStringRef alice_dsid
= SOSAccountCopyDeviceID(alice_account
, &error
);
342 ok(CFEqualSafe(alice_dsid
, CFSTR("Alice")), "Getting IDS device ID");
344 ok(SOSAccountSetMyDSID_wTxn(bob_account
, CFSTR("Bob"),&error
), "Setting IDS device ID");
345 CFStringRef bob_dsid
= SOSAccountCopyDeviceID(bob_account
, &error
);
346 ok(CFEqualSafe(bob_dsid
, CFSTR("Bob")), "Getting IDS device ID");
348 is(ProcessChangesUntilNoChange(changes
, alice_account
, bob_account
, NULL
), 3, "updates");
350 ok(SOSAccountEnsurePeerRegistration(alice_account
, NULL
), "ensure peer registration - alice");
351 ok(SOSAccountEnsurePeerRegistration(bob_account
, NULL
), "ensure peer registration - bob");
353 ids_test_sync(alice_account
, bob_account
);
355 SOSUnregisterAllTransportMessages();
356 SOSUnregisterAllTransportCircles();
357 SOSUnregisterAllTransportKeyParameters();
358 CFArrayRemoveAllValues(key_transports
);
359 CFArrayRemoveAllValues(circle_transports
);
360 CFArrayRemoveAllValues(message_transports
);
361 CFReleaseNull(alice_account
);
362 CFReleaseNull(bob_account
);
363 CFReleaseNull(changes
);
366 int secd_201_coders(int argc
, char *const *argv
)
368 plan_tests(kTestTestCount
);
370 secd_test_setup_temp_keychain(__FUNCTION__
, NULL
);