2 * Copyright (c) 2012-2014 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@
25 #include <SecureObjectSync/SOSEngine.h>
26 #include <SecureObjectSync/SOSPeer.h>
28 #include "SOSCircle_regressions.h"
30 #include <corecrypto/ccsha2.h>
32 #include <utilities/SecCFWrappers.h>
36 #include <AssertMacros.h>
41 #include <CoreFoundation/CFDate.h>
43 #include <utilities/SecCFWrappers.h>
45 #include <Security/SecKey.h>
47 #include <SecureObjectSync/SOSPeerInfo.h>
48 #include <SecureObjectSync/SOSCircle.h>
49 #include <SecureObjectSync/SOSCloudCircle.h>
50 #include <SecureObjectSync/SOSInternal.h>
51 #include <SecureObjectSync/SOSUserKeygen.h>
52 #include <SecureObjectSync/SOSPeerCoder.h>
53 #include <SecureObjectSync/SOSTransportMessageKVS.h>
54 #include <SecureObjectSync/SOSTransportMessage.h>
56 #include <SecureObjectSync/SOSAccountPriv.h>
58 #include "SOSCircle_regressions.h"
59 #include "SOSRegressionUtilities.h"
60 #include "SOSTestDataSource.h"
62 #include <securityd/Regressions/SOSAccountTesting.h>
63 #include <securityd/Regressions/SOSTransportTestTransports.h>
65 #ifndef SEC_CONST_DECL
66 #define SEC_CONST_DECL(k,v) CFTypeRef k = (CFTypeRef)(CFSTR(v));
69 #include <securityd/SOSCloudCircleServer.h>
72 // MARK: ----- Constants -----
74 static CFStringRef circleKey
= CFSTR("Circle");
76 static int kTestTestCount
= 68;
78 static bool withEngine(SOSCircleRef circle
, SOSDataSourceFactoryRef factory
, bool readOnly
, CFErrorRef
*error
, bool (^action
)(SOSEngineRef engine
, CFErrorRef
*block_error
)) {
80 SOSDataSourceRef ds
= NULL
;
81 SOSEngineRef engine
= NULL
;
83 ds
= factory
->create_datasource(factory
, SOSCircleGetName(circle
), error
);
84 require_quiet(ds
, exit
);
86 engine
= SOSEngineCreate(ds
, error
); // Hand off DS to engine.
88 require_quiet(engine
, exit
);
90 success
= action(engine
, error
);
94 SOSEngineDispose(engine
);
99 static bool SOSCircleSyncWithPeer(SOSAccountRef account
,SOSFullPeerInfoRef myRef
, SOSCircleRef circle
, SOSDataSourceFactoryRef factory
,
100 SOSPeerInfoRef peerInfo
, CFErrorRef
*error
)
102 return withEngine(circle
, factory
, true, error
, ^bool(SOSEngineRef engine
, CFErrorRef
*block_error
) {
103 SOSPeerRef peer
= SOSPeerCreate(engine
, peerInfo
, block_error
);
104 if (!peer
) return false;
106 CFMutableDictionaryRef circleToPeerIDs
= CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault
);
107 CFMutableArrayRef peer_ids
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
108 CFArrayAppendValue(peer_ids
, SOSPeerGetID(peer
));
109 CFDictionaryAddValue(circleToPeerIDs
, SOSCircleGetName(circle
), peer_ids
);
111 SOSTransportMessageRef transport
= (SOSTransportMessageRef
)CFDictionaryGetValue(SOSAccountGetMessageTransports(account
), SOSCircleGetName(circle
));
113 bool result
= SOSTransportMessageSyncWithPeers(transport
, circleToPeerIDs
, error
);
119 static bool SOSCircleHandlePeerMessage(SOSAccountRef account
, SOSCircleRef circle
, SOSFullPeerInfoRef myRef
, SOSDataSourceFactoryRef factory
,
120 SOSPeerInfoRef peerInfo
, CFDataRef message
, CFErrorRef
*error
) {
122 return withEngine(circle
, factory
, true, error
, ^bool(SOSEngineRef engine
, CFErrorRef
*block_error
) {
123 CFDataRef decodedMessage
= NULL
;
124 SOSPeerRef peer
= SOSPeerCreate(engine
, peerInfo
, block_error
);
125 if (!peer
) return false;
126 CFDictionaryRef message_transports
= (CFDictionaryRef
)SOSAccountGetMessageTransports(account
);
127 SOSTransportMessageRef transport
= (SOSTransportMessageRef
)CFDictionaryGetValue(message_transports
, SOSCircleGetName(circle
));
128 bool result
= SOSTransportMessageHandlePeerMessage(transport
, SOSPeerGetID(peer
), message
, error
);
131 CFReleaseNull(decodedMessage
);
140 CFErrorRef error
= NULL
;
142 CFStringRef aliceID
= CFSTR("Alice");
143 CFStringRef bobID
= CFSTR("Bob"); // not really remote, just another client on same machine
145 SecKeyRef alice_key
= NULL
;
146 SecKeyRef bob_key
= NULL
;
148 CFDataRef cfpassword
= CFDataCreate(NULL
, (uint8_t *) "FooFooFoo", 10);
150 CFDataRef parameters
= SOSUserKeyCreateGenerateParameters(&error
);
151 ok(parameters
, "No parameters!");
152 ok(error
== NULL
, "Error: (%@)", error
);
153 CFReleaseNull(error
);
155 SecKeyRef user_privkey
= SOSUserKeygen(cfpassword
, parameters
, &error
);
156 CFReleaseNull(parameters
);
157 CFReleaseSafe(cfpassword
);
159 CFStringRef circleName
= CFSTR("Woot Circle");
160 SOSAccountRef alice_account
= CreateAccountForLocalChanges(CFSTR("Alice"), circleName
);
161 SOSAccountRef bob_account
= CreateAccountForLocalChanges(CFSTR("Bob"), circleName
);
164 SOSFullPeerInfoRef alice_full_peer_info
= SOSCreateFullPeerInfoFromName(aliceID
, &alice_key
, &error
);
165 SOSPeerInfoRef alice_peer_info
= SOSFullPeerInfoGetPeerInfo(alice_full_peer_info
);
167 SOSFullPeerInfoRef bob_full_peer_info
= SOSCreateFullPeerInfoFromName(bobID
, &bob_key
, &error
);
168 SOSPeerInfoRef bob_peer_info
= SOSFullPeerInfoGetPeerInfo(bob_full_peer_info
);
170 SOSCircleRef aliceCircle
= SOSCircleCreate(kCFAllocatorDefault
, circleName
, &error
);
172 ok(SOSCircleRequestAdmission(aliceCircle
, user_privkey
, alice_full_peer_info
, &error
));
173 ok(SOSCircleAcceptRequests(aliceCircle
, user_privkey
, alice_full_peer_info
, NULL
));
174 ok(SOSCircleRequestAdmission(aliceCircle
, user_privkey
, bob_full_peer_info
, &error
), "requested admission");
175 ok(SOSCircleAcceptRequests(aliceCircle
, user_privkey
, bob_full_peer_info
, &error
), "accepted them all!");
177 alice_peer_info
= SOSFullPeerInfoGetPeerInfo(alice_full_peer_info
);
178 bob_peer_info
= SOSFullPeerInfoGetPeerInfo(bob_full_peer_info
);
180 CFDataRef aliceCircleEncoded
;
181 ok(aliceCircleEncoded
= SOSCircleCopyEncodedData(aliceCircle
, kCFAllocatorDefault
, &error
), "encode alice circle: %@", error
);
182 CFReleaseNull(error
);
183 SOSCircleRef bobCircle
;
184 ok(bobCircle
= SOSCircleCreateFromData(0, aliceCircleEncoded
, &error
), "decode bobCircle: %@", error
);
185 CFReleaseNull(aliceCircleEncoded
);
186 CFReleaseNull(error
);
188 SOSTransportMessageRef alice_message_transport
= (SOSTransportMessageRef
)CFDictionaryGetValue(SOSAccountGetMessageTransports(alice_account
), circleName
);
189 SOSTransportMessageRef bob_message_transport
= (SOSTransportMessageRef
)CFDictionaryGetValue(bob_account
->message_transports
, circleName
);
191 ok(SOSPeerCoderInitializeForPeer(alice_message_transport
, alice_full_peer_info
, bob_peer_info
, NULL
));
192 ok(SOSPeerCoderInitializeForPeer(bob_message_transport
, bob_full_peer_info
, alice_peer_info
, NULL
));
194 SOSDataSourceFactoryRef aliceDsf
= alice_account
->factory
;
195 SOSDataSourceFactoryRef bobDsf
= bob_account
->factory
;
197 /* Test passing peer messages to the engine. */
200 ok(SOSCircleSyncWithPeer(alice_account
, alice_full_peer_info
, aliceCircle
, aliceDsf
, bob_peer_info
, &error
), "Start sync [error %@]", error
);
201 CFReleaseNull(error
);
203 ok(CFDictionaryGetCount(SOSTransportMessageTestGetChanges((SOSTransportMessageTestRef
)alice_message_transport
)) != 0, "Alice sent message");
204 CFDictionaryRef changes
= SOSTransportMessageTestGetChanges((SOSTransportMessageTestRef
)alice_message_transport
);
205 CFDictionaryRef peer_dict
= CFDictionaryGetValue(changes
, circleName
);
206 message
= CFDictionaryGetValue(peer_dict
, SOSPeerInfoGetPeerID(bob_peer_info
));
207 is(SOSCircleHandlePeerMessage(bob_account
, bobCircle
, bob_full_peer_info
, bobDsf
, alice_peer_info
, message
, &error
), true,
208 "Bob accepted message: %@", error
);
210 is(SOSCircleSyncWithPeer(bob_account
, bob_full_peer_info
, bobCircle
, bobDsf
, alice_peer_info
, &error
), true, "Bob sent response");
211 CFReleaseNull(error
);
214 ok(CFDictionaryGetCount(SOSTransportMessageTestGetChanges((SOSTransportMessageTestRef
)bob_message_transport
)) != 0, "we got a message from Bob");
215 changes
= SOSTransportMessageTestGetChanges((SOSTransportMessageTestRef
)bob_message_transport
);
216 peer_dict
= CFDictionaryGetValue(changes
, circleName
);
217 message
= CFDictionaryGetValue(peer_dict
, SOSPeerInfoGetPeerID(alice_peer_info
));
219 ok(SOSCircleHandlePeerMessage(alice_account
, aliceCircle
, alice_full_peer_info
, aliceDsf
, bob_peer_info
, message
, &error
),
220 "Alice accepted message: %@", error
);
222 ok(CFDictionaryGetCount(SOSTransportMessageTestGetChanges((SOSTransportMessageTestRef
)alice_message_transport
)) != 0, "we got a reply from Alice");
223 changes
= SOSTransportMessageTestGetChanges((SOSTransportMessageTestRef
)alice_message_transport
);
224 peer_dict
= CFDictionaryGetValue(changes
, circleName
);
225 message
= CFDictionaryGetValue(peer_dict
, SOSPeerInfoGetPeerID(bob_peer_info
));
226 ok(SOSCircleHandlePeerMessage(bob_account
, bobCircle
, bob_full_peer_info
, bobDsf
, alice_peer_info
, message
, &error
),
227 "Bob accepted message: %@", error
);
231 SOSDataSourceRef aliceDs
= aliceDsf
->create_datasource(aliceDsf
, circleName
, NULL
);
232 ok(CFDictionaryGetCount(SOSTransportMessageTestGetChanges((SOSTransportMessageTestRef
)bob_message_transport
)) == 0, "we got no message from Bob");
234 SOSObjectRef object
= SOSDataSourceCreateGenericItem(aliceDs
, CFSTR("75_circle_engine_account"), CFSTR("test service"));
235 ok(SOSTestDataSourceAddObject(aliceDs
, object
, &error
), "add empty object to datasource: %@", error
);
236 CFReleaseNull(error
);
237 CFReleaseNull(object
);
239 ok(SOSCircleSyncWithPeer(alice_account
, alice_full_peer_info
, aliceCircle
, aliceDsf
, bob_peer_info
, &error
), "Restart sync [error %@]", error
);
240 CFReleaseNull(error
);
242 ok(CFDictionaryGetCount(SOSTransportMessageTestGetChanges((SOSTransportMessageTestRef
)alice_message_transport
)) != 0, "Alice started again");
243 changes
= SOSTransportMessageTestGetChanges((SOSTransportMessageTestRef
)alice_message_transport
);
244 peer_dict
= CFDictionaryGetValue(changes
, circleName
);
245 message
= CFDictionaryGetValue(peer_dict
, SOSPeerInfoGetPeerID(bob_peer_info
));
247 is(SOSCircleHandlePeerMessage(bob_account
, bobCircle
, bob_full_peer_info
, bobDsf
, alice_peer_info
, message
, &error
), true,
248 "bob accepted %@", message
);
249 CFReleaseNull(error
);
255 changes
= SOSTransportMessageTestGetChanges((SOSTransportMessageTestRef
)alice_message_transport
);
256 while (max_loops
-- && (CFDictionaryGetCount(changes
) != 0)) {
257 peer_dict
= CFDictionaryGetValue(changes
, circleName
);
258 message
= CFDictionaryGetValue(peer_dict
, SOSPeerInfoGetPeerID(bob_peer_info
));
260 ok(SOSCircleHandlePeerMessage(alice_account
, aliceCircle
, alice_full_peer_info
, aliceDsf
, bob_peer_info
, message
, &error
),
261 "alice accepted %@: %@", message
, error
);
263 ok(SOSCircleHandlePeerMessage(bob_account
, bobCircle
, bob_full_peer_info
, bobDsf
, alice_peer_info
, message
, &error
),
264 "bob accepted %@: %@", message
, error
);
270 CFReleaseNull(aliceCircle
);
271 CFReleaseNull(bobCircle
);
273 CFReleaseNull(alice_peer_info
);
274 CFReleaseNull(bob_peer_info
);
276 aliceDsf
->release(aliceDsf
);
277 bobDsf
->release(bobDsf
);
279 SOSUnregisterAllTransportMessages();
280 SOSUnregisterAllTransportCircles();
281 SOSUnregisterAllTransportKeyParameters();
282 CFArrayRemoveAllValues(key_transports
);
283 CFArrayRemoveAllValues(circle_transports
);
284 CFArrayRemoveAllValues(message_transports
);
287 // MARK: ----- start of all tests -----
289 int sc_75_circle_engine(int argc
, char *const *argv
)
291 plan_tests(kTestTestCount
);