5 // Created by Michael Brouwer on 8/2/12.
6 // Copyright 2012 Apple Inc. All rights reserved.
10 #include <SecureObjectSync/SOSEngine.h>
11 #include <SecureObjectSync/SOSPeer.h>
13 #include "SOSCircle_regressions.h"
15 #include <corecrypto/ccsha2.h>
16 #include <Security/SecBase64.h>
18 #include <utilities/SecCFWrappers.h>
21 #include "SOSTestDataSource.h"
22 #include "SOSTestTransport.h"
24 static int kTestTestCount
= 61;
26 static void tests(void)
28 CFErrorRef error
= NULL
;
31 __block
unsigned msg_count
= 0;
32 uint8_t msg_digest_buffer
[CCSHA256_OUTPUT_SIZE
];
33 uint8_t *msg_digest
= msg_digest_buffer
;
35 SOSPeerSendBlock sendBlock
= ^bool (CFDataRef message
, CFErrorRef
*error
) {
36 size_t msglen
= CFDataGetLength(message
);
37 const uint8_t *msg
= CFDataGetBytePtr(message
);
38 const struct ccdigest_info
*sha256
= ccsha256_di();
39 if (msg_count
++ == 0) {
41 ccdigest(sha256
, msglen
, msg
, msg_digest
);
44 ccdigest_di_decl(sha256
, sha256_ctx
);
45 ccdigest_init(sha256
, sha256_ctx
);
46 ccdigest_update(sha256
, sha256_ctx
, sizeof(msg_digest_buffer
), msg_digest
);
47 ccdigest_update(sha256
, sha256_ctx
, msglen
, msg
);
48 ccdigest_final(sha256
, sha256_ctx
, msg_digest
);
50 size_t encmaxlen
= SecBase64Encode(msg
, msglen
, NULL
, 0);
51 CFMutableDataRef encoded
= CFDataCreateMutable(NULL
, encmaxlen
);
52 CFDataSetLength(encoded
, encmaxlen
);
54 char *enc
= (char *)CFDataGetMutableBytePtr(encoded
);
58 SecBase64Encode2(msg
, msglen
,
60 encmaxlen
, kSecB64_F_LINE_LEN_USE_PARAM
,
62 assert(enclen
< INT32_MAX
);
63 // printf("=== BEGIN SOSMESSAGE ===\n%.*s\n=== END SOSMESSAGE ===\n", (int)enclen, enc);
68 /* Create peer test. */
69 CFStringRef peer_id
= CFSTR("peer 70");
71 ok(peer
= SOSPeerCreateSimple(peer_id
, kSOSPeerVersion
, &error
, sendBlock
),
72 "create peer: %@", error
);
76 SOSDataSourceRef ds
= SOSTestDataSourceCreate();
78 /* Create engine test. */
80 ok(engine
= SOSEngineCreate(ds
, &error
), "create engine: %@", error
);
83 /* Make sure the engine did not yet send a any messages to the peer. */
84 unsigned expected_msg_count
= 0;
85 is(msg_count
, expected_msg_count
, "Engine sent %d/%d messages",
86 msg_count
, expected_msg_count
);
88 /* Test passing peer messages to the engine. */
91 /* Hand an empty message to the engine for handeling. */
92 message
= CFDataCreate(NULL
, NULL
, 0);
93 ok(false == SOSEngineHandleMessage(engine
, peer
, message
, &error
),
94 "handle empty message: %@", error
);
96 CFReleaseNull(message
);
97 /* Make sure the engine did not yet send a response to the peer. */
98 is(msg_count
, expected_msg_count
, "Engine sent %d/%d messages",
99 msg_count
, expected_msg_count
);
102 /* Create manifest digest message. */
104 skip("Create manifest digest message failed", 2,
105 ok(message
= SOSEngineCreateManifestDigestMessage(engine
, peer
,
107 "create manifest digest message: %@", error
));
108 CFReleaseNull(error
);
109 /* Pass manifest digest message to the engine for handeling. */
111 ok(SOSEngineHandleMessage(engine
, peer
, message
, &error
),
112 "handle manifest digest message: %@", error
));
113 /* Make sure the engine sent a response to the peer. */
114 expected_msg_count
++;
115 is(msg_count
, expected_msg_count
, "Engine sent %d/%d messages",
116 msg_count
, expected_msg_count
);
118 CFReleaseNull(message
);
119 CFReleaseNull(error
);
121 /* Create manifest message. */
123 skip("Create manifest message failed", 2,
124 ok(message
= SOSEngineCreateManifestMessage(engine
, peer
, &error
),
125 "create manifest message: %@", error
));
126 CFReleaseNull(error
);
127 /* Pass manifest message to the engine for handeling. */
129 ok(SOSEngineHandleMessage(engine
, peer
, message
, &error
),
130 "handle manifest message: %@", error
));
131 /* Make sure the engine sent a response to the peer. */
132 expected_msg_count
++;
133 is(msg_count
, expected_msg_count
, "Engine sent %d/%d messages",
134 msg_count
, expected_msg_count
);
136 CFReleaseNull(message
);
137 CFReleaseNull(error
);
139 /* Create manifest and objects message. */
141 skip("Create manifest and objects message failed", 2,
142 ok(message
= SOSEngineCreateManifestAndObjectsMessage(engine
, peer
,
144 "create manifest and objects message: %@", error
));
145 CFReleaseNull(error
);
146 /* Pass manifest and objects message to the engine for handeling. */
148 ok(SOSEngineHandleMessage(engine
, peer
, message
, &error
),
149 "handle manifest and objects message: %@", error
));
150 /* Make sure the engine sent a response to the peer. */
151 expected_msg_count
++;
152 is(msg_count
, expected_msg_count
, "Engine sent %d/%d messages",
153 msg_count
, expected_msg_count
);
155 CFReleaseNull(message
);
156 CFReleaseNull(error
);
159 SOSPeerDispose(peer
);
160 SOSEngineDispose(engine
);
163 static CFStringRef
SOSMessageCopyDigestHex(CFDataRef message
) {
164 uint8_t digest
[CCSHA1_OUTPUT_SIZE
];
165 ccdigest(ccsha1_di(), CFDataGetLength(message
), CFDataGetBytePtr(message
), digest
);
166 CFMutableStringRef hex
= CFStringCreateMutable(0, 2 * sizeof(digest
));
167 for (unsigned int ix
= 0; ix
< sizeof(digest
); ++ix
) {
168 CFStringAppendFormat(hex
, 0, CFSTR("%02X"), digest
[ix
]);
173 static void testsync(const char *name
, void (^aliceInit
)(SOSDataSourceRef ds
), void (^bobInit
)(SOSDataSourceRef ds
), CFStringRef msg
, ...) {
174 CFErrorRef error
= NULL
;
176 /* Setup Alice engine, dataSource and peer for Alice to talk to Bob */
177 SOSDataSourceRef aliceDataSource
= SOSTestDataSourceCreate();
178 SOSEngineRef aliceEngine
;
179 ok(aliceEngine
= SOSEngineCreate(aliceDataSource
, &error
), "create alice engine: %@", error
);
180 CFReleaseNull(error
);
181 CFStringRef bobID
= CFStringCreateWithFormat(kCFAllocatorDefault
, 0, CFSTR("Bob-%s"), name
);
183 __block CFDataRef queued_message
= NULL
;
185 SOSPeerSendBlock enqueueMessage
= ^bool (CFDataRef message
, CFErrorRef
*error
) {
187 fail("We already had an unproccessed message");
189 queued_message
= (CFDataRef
) CFRetain(message
);
193 CFDataRef (^dequeueMessage
)() = ^CFDataRef () {
194 CFDataRef result
= queued_message
;
195 queued_message
= NULL
;
201 ok(bobPeer
= SOSPeerCreateSimple(bobID
, kSOSPeerVersion
, &error
, enqueueMessage
),
202 "create peer: %@", error
);
204 /* Setup Bob engine, dataSource and peer for Bob to talk to Alice */
205 SOSDataSourceRef bobDataSource
= SOSTestDataSourceCreate();
206 SOSEngineRef bobEngine
;
207 ok(bobEngine
= SOSEngineCreate(bobDataSource
, &error
), "create bob engine: %@", error
);
208 CFReleaseNull(error
);
209 CFStringRef aliceID
= CFStringCreateWithFormat(kCFAllocatorDefault
, 0, CFSTR("Alice-%s"), name
);
211 SOSPeerRef alicePeer
;
212 ok(alicePeer
= SOSPeerCreateSimple(aliceID
, kSOSPeerVersion
, &error
, enqueueMessage
),
213 "create peer: %@", error
);
214 CFReleaseNull(error
);
216 /* Now call provided setup blocks to populate the dataSources with
217 interesting stuff. */
218 aliceInit(aliceDataSource
);
219 bobInit(bobDataSource
);
221 /* Start syncing by making alice send the first message. */
222 ok(SOSEngineSyncWithPeer(aliceEngine
, bobPeer
, false, &error
), "tell Alice sync with peer Bob");
231 message
= dequeueMessage();
233 /* We are expecting a message and msg is it's digest. */
235 CFStringRef messageDesc
= SOSMessageCopyDescription(message
);
236 CFStringRef messageDigestStr
= SOSMessageCopyDigestHex(message
);
238 bool handeled
= SOSEngineHandleMessage(alice
? aliceEngine
: bobEngine
, alice
? bobPeer
: alicePeer
, message
, &error
);
239 if (!CFEqual(messageDigestStr
, msg
)) {
241 fail("%s %s received message [%d] digest %@ != %@ %@", name
, alice
? "Alice" : "Bob", msg_index
, messageDigestStr
, msg
, messageDesc
);
243 fail("%s %s failed to handle message [%d] digest %@ != %@ %@: %@", name
, alice
? "Alice" : "Bob", msg_index
, messageDigestStr
, msg
, messageDesc
, error
);
244 CFReleaseNull(error
);
246 } else if (handeled
) {
247 pass("%s %s handled message [%d] %@", name
, alice
? "Alice" : "Bob", msg_index
, messageDesc
);
249 fail("%s %s failed to handle message [%d] %@: %@", name
, alice
? "Alice" : "Bob", msg_index
, messageDesc
, error
);
250 CFReleaseNull(error
);
253 fail("%s %s sent extra message [%d] with digest %@: %@", name
, alice
? "Bob" : "Alice", msg_index
, messageDigestStr
, messageDesc
);
255 CFRelease(messageDigestStr
);
256 CFRelease(messageDesc
);
260 fail("%s %s expected message [%d] with digest %@, none received", name
, alice
? "Alice" : "Bob", msg_index
, msg
);
262 /* Compare alice and bobs dataSources databases. */
263 ok(CFEqual(SOSTestDataSourceGetDatabase(aliceDataSource
), SOSTestDataSourceGetDatabase(bobDataSource
)), "%s Alice and Bob are in sync", name
);
269 msg
= va_arg(msgs
, CFStringRef
);
276 SOSEngineDispose(aliceEngine
); // Also disposes aliceDataSource
277 SOSPeerDispose(alicePeer
);
278 CFReleaseSafe(aliceID
);
280 SOSEngineDispose(bobEngine
); // Also disposes bobDataSource
281 SOSPeerDispose(bobPeer
);
282 CFReleaseSafe(bobID
);
285 static void synctests(void) {
286 // Sync between 2 empty dataSources
288 ^ (SOSDataSourceRef dataSource
) {},
289 ^ (SOSDataSourceRef dataSource
) {},
290 CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"),
291 CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"),
292 CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"),
295 // Sync a dataSource with one object to an empty dataSource
297 ^ (SOSDataSourceRef dataSource
) {
298 CFErrorRef error
= NULL
;
299 SOSObjectRef object
= SOSDataSourceCreateGenericItem(dataSource
, CFSTR("test_account"), CFSTR("test service"));
300 ok(dataSource
->add(dataSource
, object
, &error
), "dataSource added object %@", error
);
301 CFReleaseSafe(object
);
302 CFReleaseNull(error
);
304 ^ (SOSDataSourceRef dataSource
) {},
305 CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"),
306 CFSTR("147B6C509908CC4A9FC4263973A842104A64CE01"),
307 CFSTR("019B494F3C06B48BB02C280AF1E19AD861A7003C"),
308 CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"),
311 // Sync a dataSource with one object to another dataSource with the same object
312 testsync("alice1bob1",
313 ^ (SOSDataSourceRef dataSource
) {
314 CFErrorRef error
= NULL
;
315 SOSObjectRef object
= SOSDataSourceCreateGenericItem(dataSource
, CFSTR("test_account"), CFSTR("test service"));
316 ok(dataSource
->add(dataSource
, object
, &error
), "dataSource added object %@", error
);
317 CFReleaseSafe(object
);
318 CFReleaseNull(error
);
320 ^ (SOSDataSourceRef dataSource
) {
321 CFErrorRef error
= NULL
;
322 SOSObjectRef object
= SOSDataSourceCreateGenericItem(dataSource
, CFSTR("test_account"), CFSTR("test service"));
323 ok(dataSource
->add(dataSource
, object
, &error
), "dataSource added object %@", error
);
324 CFReleaseSafe(object
);
325 CFReleaseNull(error
);
327 CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"),
328 CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"),
329 CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"),
332 // Sync a dataSource with one object to another dataSource with the same object
333 testsync("alice1bob2",
334 ^ (SOSDataSourceRef dataSource
) {
335 CFErrorRef error
= NULL
;
336 SOSObjectRef object
= SOSDataSourceCreateGenericItem(dataSource
, CFSTR("test_account"), CFSTR("test service"));
337 ok(dataSource
->add(dataSource
, object
, &error
), "dataSource added object %@", error
);
338 CFReleaseSafe(object
);
339 CFReleaseNull(error
);
341 ^ (SOSDataSourceRef dataSource
) {
342 CFErrorRef error
= NULL
;
343 SOSObjectRef object
= SOSDataSourceCreateGenericItem(dataSource
, CFSTR("test_account"), CFSTR("test service"));
344 ok(dataSource
->add(dataSource
, object
, &error
), "dataSource added object %@", error
);
345 CFReleaseSafe(object
);
346 object
= SOSDataSourceCreateGenericItem(dataSource
, CFSTR("account1"), CFSTR("service1"));
347 ok(dataSource
->add(dataSource
, object
, &error
), "dataSource added object %@", error
);
348 CFReleaseSafe(object
);
349 CFReleaseNull(error
);
351 CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"),
352 CFSTR("D4049A1063CFBF7CAF8424E13DE3CE926FF5856C"),
353 CFSTR("9624EA855BBED6B668868BB723443E804D04F6A1"),
354 CFSTR("063E097CCD4FEB7F3610ED12B3DA828467314846"),
355 CFSTR("D1B3944E3084425F41B2C2EA0BE82170E10AA37D"),
360 int sc_70_engine(int argc
, char *const *argv
)
362 plan_tests(kTestTestCount
);