]> git.saurik.com Git - apple/security.git/blob - OSX/sec/securityd/Regressions/secd-668-ghosts.m
Security-58286.1.32.tar.gz
[apple/security.git] / OSX / sec / securityd / Regressions / secd-668-ghosts.m
1 /*
2 * Copyright (c) 2012-2016 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 //
25 // secd-668-ghosts.c
26 // sec
27 //
28
29 #include <CoreFoundation/CFDictionary.h>
30 #include <utilities/SecCFWrappers.h>
31
32 #include <Security/SecureObjectSync/SOSAccount.h>
33 #include <Security/SecureObjectSync/SOSAccountTrustClassic+Circle.h>
34
35 #include "secd_regressions.h"
36 #include "SOSAccountTesting.h"
37 #include "SecdTestKeychainUtilities.h"
38
39 static int kTestTestCount = 530;
40
41 /*
42 Make a circle with two peers - alice and bob(bob is iOS and serial#"abababababab")
43 have alice leave the circle
44 release bob, make a new bob - iOS and same serial number
45 try to join the circle - it should resetToOffering with ghost fix
46
47 For phase 1 we expect the ghostfix to work with iOS devices, but not with MacOSX devices.
48 */
49
50 static void hauntedCircle(SOSPeerInfoDeviceClass devClass, bool expectGhostBusted)
51 {
52 CFErrorRef error = NULL;
53 CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10);
54 CFStringRef cfaccount = CFSTR("test@test.org");
55 CFStringRef ghostSerialID = CFSTR("abababababab");
56 CFStringRef ghostIdsID = CFSTR("targetIDS");
57
58 CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
59 SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource"));
60 SOSAccount* bob_account = SOSTestCreateAccountAsSerialClone(CFSTR("Bob"), devClass, ghostSerialID, ghostIdsID);
61
62 // Start Circle
63 ok(SOSTestStartCircleWithAccount(alice_account, changes, cfaccount, cfpassword), "Have Alice start a circle");
64 is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates");
65 ok(SOSTestJoinWithApproval(cfpassword, cfaccount, changes, alice_account, bob_account, KEEP_USERKEY, 2, false), "Bob Joins");
66
67 // Alice Leaves
68 ok( [alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves (%@)", error);
69 CFReleaseNull(error);
70 is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates");
71 accounts_agree("Alice bails", bob_account, alice_account);
72 is(countPeers(bob_account), 1, "There should only be 1 valid peer");
73 // We're dropping all peers that are in the circle - leaving a circle with only one peer - and that's a ghost
74
75 // Make new bob - same as the old bob except peerID
76
77 SOSAccount* bobFinal = SOSTestCreateAccountAsSerialClone(CFSTR("BobFinal"), devClass, ghostSerialID, ghostIdsID);
78 ok(SOSTestJoinWith(cfpassword, cfaccount, changes, bobFinal), "Application Made");
79 CFReleaseNull(cfpassword);
80
81 // Did ghostbuster work?
82 is(ProcessChangesUntilNoChange(changes, bobFinal, NULL), 2, "updates");
83 if(expectGhostBusted) { // ghostbusting is currently disabled for MacOSX Peers
84 ok([bobFinal.trust isInCircle:NULL], "Bob is in");
85 } else {
86 ok(![bobFinal.trust isInCircle:NULL], "Bob is not in");
87 }
88
89 is(countPeers(bobFinal), 1, "There should only be 1 valid peer");
90
91 CFReleaseNull(changes);
92
93 bob_account = nil;
94 alice_account = nil;
95 bobFinal = nil;
96 SOSTestCleanup();
97 }
98
99 static void multiBob(SOSPeerInfoDeviceClass devClass, bool expectGhostBusted, bool delayedPrivKey) {
100 CFErrorRef error = NULL;
101 CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10);
102 CFStringRef cfaccount = CFSTR("test@test.org");
103 CFStringRef ghostSerialID = CFSTR("abababababab");
104 CFStringRef ghostIdsID = CFSTR("targetIDS");
105
106 CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
107 SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource"));
108
109 // Start Circle
110 ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error);
111 is(ProcessChangesUntilNoChange(changes, alice_account, NULL), 1, "updates");
112
113 ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error);
114 CFReleaseNull(error);
115
116 is(ProcessChangesUntilNoChange(changes, alice_account, NULL), 1, "updates");
117
118 SOSTestMakeGhostInCircle(CFSTR("Bob1"), devClass, ghostSerialID, ghostIdsID, cfpassword, cfaccount, changes, alice_account, 2);
119 SOSTestMakeGhostInCircle(CFSTR("Bob2"), devClass, ghostSerialID, ghostIdsID, cfpassword, cfaccount, changes, alice_account, 3);
120 SOSTestMakeGhostInCircle(CFSTR("Bob3"), devClass, ghostSerialID, ghostIdsID, cfpassword, cfaccount, changes, alice_account, 4);
121 SOSTestMakeGhostInCircle(CFSTR("Bob4"), devClass, ghostSerialID, ghostIdsID, cfpassword, cfaccount, changes, alice_account, 5);
122
123 SOSAccount* bobFinal_account = SOSTestCreateAccountAsSerialClone(CFSTR("BobFinal"), devClass, ghostSerialID, ghostIdsID);
124 if(delayedPrivKey) {
125 SOSTestJoinWithApproval(cfpassword, cfaccount, changes, alice_account, bobFinal_account, DROP_USERKEY, 6, true);
126 is(countPeers(bobFinal_account), 6, "Expect ghosts still in circle");
127 SOSAccountTryUserCredentials(bobFinal_account, cfaccount, cfpassword, &error);
128 ok(SOSTestChangeAccountDeviceName(bobFinal_account, CFSTR("ThereCanBeOnlyOneBob")), "force an unrelated circle change");
129 is(ProcessChangesUntilNoChange(changes, alice_account, bobFinal_account, NULL), 3, "updates");
130 } else {
131 SOSTestJoinWithApproval(cfpassword, cfaccount, changes, alice_account, bobFinal_account, KEEP_USERKEY, 2, true);
132 }
133 CFReleaseNull(cfpassword);
134
135 is(countPeers(bobFinal_account), 2, "Expect ghostBobs to be gone");
136 is(countPeers(alice_account), 2, "Expect ghostBobs to be gone");
137 accounts_agree_internal("Alice and ThereCanBeOnlyOneBob are the only circle peers and they agree", alice_account, bobFinal_account, false);
138
139 CFReleaseNull(changes);
140
141 alice_account = nil;
142 bobFinal_account = nil;
143
144 SOSTestCleanup();
145 }
146
147 static void iosICloudIdentity() {
148 CFErrorRef error = NULL;
149 CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10);
150 CFStringRef cfaccount = CFSTR("test@test.org");
151 CFStringRef ghostIdsID = CFSTR("targetIDS");
152
153 CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
154 SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource"));
155
156 // Start Circle
157 ok(SOSTestStartCircleWithAccount(alice_account, changes, cfaccount, cfpassword), "Have Alice start a circle");
158
159 SOSCircleRef circle = [alice_account.trust getCircle:NULL];
160 __block CFStringRef serial = NULL;
161 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
162 if(SOSPeerInfoIsCloudIdentity(peer)) {
163 serial = SOSPeerInfoCopySerialNumber(peer);
164 }
165 });
166
167 SOSAccount* bob_account = SOSTestCreateAccountAsSerialClone(CFSTR("Bob"), SOSPeerInfo_iOS, serial, ghostIdsID);
168
169 is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates");
170 ok(SOSTestJoinWithApproval(cfpassword, cfaccount, changes, alice_account, bob_account, KEEP_USERKEY, 2, false), "Bob Joins");
171 CFReleaseNull(cfpassword);
172
173 circle = [alice_account.trust getCircle:&error];
174 __block bool hasiCloudIdentity = false;
175 SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
176 if(SOSPeerInfoIsCloudIdentity(peer)) {
177 hasiCloudIdentity = true;
178 }
179 });
180
181 ok(hasiCloudIdentity, "GhostBusting didn't mess with the iCloud Identity");
182
183 CFReleaseNull(changes);
184 alice_account = nil;
185 SOSTestCleanup();
186 }
187
188 int secd_68_ghosts(int argc, char *const *argv)
189 {
190 plan_tests(kTestTestCount);
191
192 secd_test_setup_temp_keychain(__FUNCTION__, NULL);
193
194 hauntedCircle(SOSPeerInfo_iOS, true);
195 hauntedCircle(SOSPeerInfo_macOS, false);
196 multiBob(SOSPeerInfo_iOS, true, false);
197 multiBob(SOSPeerInfo_iOS, false, true);
198
199 iosICloudIdentity();
200
201 return 0;
202 }