2 * Copyright (c) 2012-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@
29 #include <CoreFoundation/CFDictionary.h>
30 #include <utilities/SecCFWrappers.h>
32 #include <Security/SecureObjectSync/SOSAccount.h>
34 #include "secd_regressions.h"
35 #include "SOSAccountTesting.h"
36 #include "SecdTestKeychainUtilities.h"
38 static int kTestTestCount
= 538;
41 Make a circle with two peers - alice and bob(bob is iOS and serial#"abababababab")
42 have alice leave the circle
43 release bob, make a new bob - iOS and same serial number
44 try to join the circle - it should resetToOffering with ghost fix
46 For phase 1 we expect the ghostfix to work with iOS devices, but not with MacOSX devices.
49 static void hauntedCircle(SOSPeerInfoDeviceClass devClass
, bool expectGhostBusted
)
51 CFErrorRef error
= NULL
;
52 CFDataRef cfpassword
= CFDataCreate(NULL
, (uint8_t *) "FooFooFoo", 10);
53 CFStringRef cfaccount
= CFSTR("test@test.org");
54 CFStringRef ghostSerialID
= CFSTR("abababababab");
55 CFStringRef ghostIdsID
= CFSTR("targetIDS");
57 CFMutableDictionaryRef changes
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
58 SOSAccountRef alice_account
= CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource"));
59 SOSAccountRef bob_account
= SOSTestCreateAccountAsSerialClone(CFSTR("Bob"), devClass
, ghostSerialID
, ghostIdsID
);
62 ok(SOSTestStartCircleWithAccount(alice_account
, changes
, cfaccount
, cfpassword
), "Have Alice start a circle");
63 is(ProcessChangesUntilNoChange(changes
, alice_account
, bob_account
, NULL
), 1, "updates");
64 ok(SOSTestJoinWithApproval(cfpassword
, cfaccount
, changes
, alice_account
, bob_account
, KEEP_USERKEY
, 2, false), "Bob Joins");
67 ok(SOSAccountLeaveCircle(alice_account
, &error
), "Alice Leaves (%@)", error
);
69 is(ProcessChangesUntilNoChange(changes
, alice_account
, bob_account
, NULL
), 2, "updates");
70 accounts_agree("Alice bails", bob_account
, alice_account
);
71 is(countPeers(bob_account
), 1, "There should only be 1 valid peer");
72 // We're dropping all peers that are in the circle - leaving a circle with only one peer - and that's a ghost
73 CFReleaseNull(alice_account
);
74 CFReleaseNull(bob_account
);
76 // Make new bob - same as the old bob except peerID
78 SOSAccountRef bobFinal
= SOSTestCreateAccountAsSerialClone(CFSTR("BobFinal"), devClass
, ghostSerialID
, ghostIdsID
);
79 ok(SOSTestJoinWith(cfpassword
, cfaccount
, changes
, bobFinal
), "Application Made");
81 // Did ghostbuster work?
82 is(ProcessChangesUntilNoChange(changes
, bobFinal
, NULL
), 2, "updates");
83 if(expectGhostBusted
) { // ghostbusting is currently disabled for MacOSX Peers
84 ok(SOSAccountIsInCircle(bobFinal
, NULL
), "Bob is in");
86 ok(!SOSAccountIsInCircle(bobFinal
, NULL
), "Bob is not in");
89 is(countPeers(bobFinal
), 1, "There should only be 1 valid peer");
91 CFReleaseNull(bobFinal
);
92 CFReleaseNull(changes
);
97 static void multiBob(SOSPeerInfoDeviceClass devClass
, bool expectGhostBusted
, bool delayedPrivKey
) {
98 CFErrorRef error
= NULL
;
99 CFDataRef cfpassword
= CFDataCreate(NULL
, (uint8_t *) "FooFooFoo", 10);
100 CFStringRef cfaccount
= CFSTR("test@test.org");
101 CFStringRef ghostSerialID
= CFSTR("abababababab");
102 CFStringRef ghostIdsID
= CFSTR("targetIDS");
104 CFMutableDictionaryRef changes
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
105 SOSAccountRef alice_account
= CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource"));
108 ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account
, cfaccount
, cfpassword
, &error
), "Credential setting (%@)", error
);
109 is(ProcessChangesUntilNoChange(changes
, alice_account
, NULL
), 1, "updates");
111 ok(SOSAccountResetToOffering_wTxn(alice_account
, &error
), "Reset to offering (%@)", error
);
112 CFReleaseNull(error
);
114 is(ProcessChangesUntilNoChange(changes
, alice_account
, NULL
), 1, "updates");
116 SOSTestMakeGhostInCircle(CFSTR("Bob1"), devClass
, ghostSerialID
, ghostIdsID
, cfpassword
, cfaccount
, changes
, alice_account
, 2);
117 SOSTestMakeGhostInCircle(CFSTR("Bob2"), devClass
, ghostSerialID
, ghostIdsID
, cfpassword
, cfaccount
, changes
, alice_account
, 3);
118 SOSTestMakeGhostInCircle(CFSTR("Bob3"), devClass
, ghostSerialID
, ghostIdsID
, cfpassword
, cfaccount
, changes
, alice_account
, 4);
119 SOSTestMakeGhostInCircle(CFSTR("Bob4"), devClass
, ghostSerialID
, ghostIdsID
, cfpassword
, cfaccount
, changes
, alice_account
, 5);
121 SOSAccountRef bobFinal_account
= SOSTestCreateAccountAsSerialClone(CFSTR("BobFinal"), devClass
, ghostSerialID
, ghostIdsID
);
123 SOSTestJoinWithApproval(cfpassword
, cfaccount
, changes
, alice_account
, bobFinal_account
, DROP_USERKEY
, 6, true);
124 is(countPeers(bobFinal_account
), 6, "Expect ghosts still in circle");
125 SOSAccountTryUserCredentials(bobFinal_account
, cfaccount
, cfpassword
, &error
);
126 ok(SOSTestChangeAccountDeviceName(bobFinal_account
, CFSTR("ThereCanBeOnlyOneBob")), "force an unrelated circle change");
127 is(ProcessChangesUntilNoChange(changes
, alice_account
, bobFinal_account
, NULL
), 3, "updates");
129 SOSTestJoinWithApproval(cfpassword
, cfaccount
, changes
, alice_account
, bobFinal_account
, KEEP_USERKEY
, 2, true);
132 is(countPeers(bobFinal_account
), 2, "Expect ghostBobs to be gone");
133 is(countPeers(alice_account
), 2, "Expect ghostBobs to be gone");
134 accounts_agree_internal("Alice and ThereCanBeOnlyOneBob are the only circle peers and they agree", alice_account
, bobFinal_account
, false);
136 CFReleaseNull(bobFinal_account
);
137 CFReleaseNull(alice_account
);
138 CFReleaseNull(changes
);
143 static void iosICloudIdentity() {
144 CFErrorRef error
= NULL
;
145 CFDataRef cfpassword
= CFDataCreate(NULL
, (uint8_t *) "FooFooFoo", 10);
146 CFStringRef cfaccount
= CFSTR("test@test.org");
147 CFStringRef ghostIdsID
= CFSTR("targetIDS");
149 CFMutableDictionaryRef changes
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
150 SOSAccountRef alice_account
= CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource"));
153 ok(SOSTestStartCircleWithAccount(alice_account
, changes
, cfaccount
, cfpassword
), "Have Alice start a circle");
155 SOSCircleRef circle
= SOSAccountGetCircle(alice_account
, &error
);
156 __block CFStringRef serial
= NULL
;
157 SOSCircleForEachActivePeer(circle
, ^(SOSPeerInfoRef peer
) {
158 if(SOSPeerInfoIsCloudIdentity(peer
)) {
159 serial
= SOSPeerInfoCopySerialNumber(peer
);
163 SOSAccountRef bob_account
= SOSTestCreateAccountAsSerialClone(CFSTR("Bob"), SOSPeerInfo_iOS
, serial
, ghostIdsID
);
165 is(ProcessChangesUntilNoChange(changes
, alice_account
, bob_account
, NULL
), 1, "updates");
166 ok(SOSTestJoinWithApproval(cfpassword
, cfaccount
, changes
, alice_account
, bob_account
, KEEP_USERKEY
, 2, false), "Bob Joins");
168 circle
= SOSAccountGetCircle(alice_account
, &error
);
169 __block
bool hasiCloudIdentity
= false;
170 SOSCircleForEachActivePeer(circle
, ^(SOSPeerInfoRef peer
) {
171 if(SOSPeerInfoIsCloudIdentity(peer
)) {
172 hasiCloudIdentity
= true;
176 ok(hasiCloudIdentity
, "GhostBusting didn't mess with the iCloud Identity");
178 CFReleaseNull(alice_account
);
179 CFReleaseNull(bob_account
);
180 CFReleaseNull(changes
);
185 int secd_668_ghosts(int argc
, char *const *argv
)
187 plan_tests(kTestTestCount
);
189 secd_test_setup_temp_keychain(__FUNCTION__
, NULL
);
191 hauntedCircle(SOSPeerInfo_iOS
, true);
192 hauntedCircle(SOSPeerInfo_macOS
, false);
193 multiBob(SOSPeerInfo_iOS
, true, false);
194 multiBob(SOSPeerInfo_iOS
, false, true);