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>
31 #include <Security/SecBase64.h>
33 #include <utilities/SecCFWrappers.h>
36 #include "SOSTestDataSource.h"
39 static int kTestTestCount
= 0;
41 static int kTestTestCount
= 61;
43 static void tests(void)
45 CFErrorRef error
= NULL
;
48 __block
unsigned msg_count
= 0;
49 uint8_t msg_digest_buffer
[CCSHA256_OUTPUT_SIZE
];
50 uint8_t *msg_digest
= msg_digest_buffer
;
52 SOSPeerSendBlock sendBlock
= ^bool (CFDataRef message
, CFErrorRef
*error
) {
53 size_t msglen
= CFDataGetLength(message
);
54 const uint8_t *msg
= CFDataGetBytePtr(message
);
55 const struct ccdigest_info
*sha256
= ccsha256_di();
56 if (msg_count
++ == 0) {
58 ccdigest(sha256
, msglen
, msg
, msg_digest
);
61 ccdigest_di_decl(sha256
, sha256_ctx
);
62 ccdigest_init(sha256
, sha256_ctx
);
63 ccdigest_update(sha256
, sha256_ctx
, sizeof(msg_digest_buffer
), msg_digest
);
64 ccdigest_update(sha256
, sha256_ctx
, msglen
, msg
);
65 ccdigest_final(sha256
, sha256_ctx
, msg_digest
);
67 size_t encmaxlen
= SecBase64Encode(msg
, msglen
, NULL
, 0);
68 CFMutableDataRef encoded
= CFDataCreateMutable(NULL
, encmaxlen
);
69 CFDataSetLength(encoded
, encmaxlen
);
71 char *enc
= (char *)CFDataGetMutableBytePtr(encoded
);
75 SecBase64Encode2(msg
, msglen
,
77 encmaxlen
, kSecB64_F_LINE_LEN_USE_PARAM
,
79 assert(enclen
< INT32_MAX
);
80 // printf("=== BEGIN SOSMESSAGE ===\n%.*s\n=== END SOSMESSAGE ===\n", (int)enclen, enc);
85 /* Create peer test. */
86 CFStringRef peer_id
= CFSTR("peer 70");
88 ok(peer
= SOSPeerCreateSimple(peer_id
, kSOSPeerVersion
, &error
),
89 "create peer: %@", error
);
93 SOSDataSourceRef ds
= SOSTestDataSourceCreate();
95 /* Create engine test. */
97 ok(engine
= SOSEngineCreate(ds
, &error
), "create engine: %@", error
);
100 /* Make sure the engine did not yet send a any messages to the peer. */
101 unsigned expected_msg_count
= 0;
102 is(msg_count
, expected_msg_count
, "Engine sent %d/%d messages",
103 msg_count
, expected_msg_count
);
105 /* Test passing peer messages to the engine. */
108 /* Hand an empty message to the engine for handeling. */
109 message
= CFDataCreate(NULL
, NULL
, 0);
110 ok(false == SOSEngineHandleMessage(engine
, peer
, message
, &error
),
111 "handle empty message: %@", error
);
112 ok(false == SOSPeerSendMessageIfNeeded(engine
, peer
, &error
, sendBlock
),
113 "send response: %@", error
);
114 CFReleaseNull(error
);
115 CFReleaseNull(message
);
116 /* Make sure the engine did not yet send a response to the peer. */
117 is(msg_count
, expected_msg_count
, "Engine sent %d/%d messages",
118 msg_count
, expected_msg_count
);
121 /* Create manifest digest message. */
123 skip("Create manifest digest message failed", 2,
124 ok(message
= SOSEngineCreateManifestDigestMessage(engine
, peer
,
126 "create manifest digest message: %@", error
));
127 CFReleaseNull(error
);
128 /* Pass manifest digest message to the engine for handeling. */
130 ok(SOSEngineHandleMessage(engine
, peer
, message
, &error
),
131 "handle manifest digest message: %@", error
));
132 /* Make sure the engine sent a response to the peer. */
133 expected_msg_count
++;
134 is(msg_count
, expected_msg_count
, "Engine sent %d/%d messages",
135 msg_count
, expected_msg_count
);
137 CFReleaseNull(message
);
138 CFReleaseNull(error
);
140 /* Create manifest message. */
142 skip("Create manifest message failed", 2,
143 ok(message
= SOSEngineCreateManifestMessage(engine
, peer
, &error
),
144 "create manifest message: %@", error
));
145 CFReleaseNull(error
);
146 /* Pass manifest message to the engine for handeling. */
148 ok(SOSEngineHandleMessage(engine
, peer
, message
, &error
),
149 "handle manifest 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
);
158 /* Create manifest and objects message. */
160 skip("Create manifest and objects message failed", 2,
161 ok(message
= SOSEngineCreateManifestAndObjectsMessage(engine
, peer
,
163 "create manifest and objects message: %@", error
));
164 CFReleaseNull(error
);
165 /* Pass manifest and objects message to the engine for handeling. */
167 ok(SOSEngineHandleMessage(engine
, peer
, message
, &error
),
168 "handle manifest and objects message: %@", error
));
169 /* Make sure the engine sent a response to the peer. */
170 expected_msg_count
++;
171 is(msg_count
, expected_msg_count
, "Engine sent %d/%d messages",
172 msg_count
, expected_msg_count
);
174 CFReleaseNull(message
);
175 CFReleaseNull(error
);
179 SOSEngineDispose(engine
);
182 static CFStringRef
SOSMessageCopyDigestHex(CFDataRef message
) {
183 uint8_t digest
[CCSHA1_OUTPUT_SIZE
];
184 ccdigest(ccsha1_di(), CFDataGetLength(message
), CFDataGetBytePtr(message
), digest
);
185 CFMutableStringRef hex
= CFStringCreateMutable(0, 2 * sizeof(digest
));
186 for (unsigned int ix
= 0; ix
< sizeof(digest
); ++ix
) {
187 CFStringAppendFormat(hex
, 0, CFSTR("%02X"), digest
[ix
]);
192 static void testsync(const char *name
, void (^aliceInit
)(SOSDataSourceRef ds
), void (^bobInit
)(SOSDataSourceRef ds
), CFStringRef msg
, ...) {
193 CFErrorRef error
= NULL
;
195 /* Setup Alice engine, dataSource and peer for Alice to talk to Bob */
196 SOSDataSourceRef aliceDataSource
= SOSTestDataSourceCreate();
197 SOSEngineRef aliceEngine
;
198 ok(aliceEngine
= SOSEngineCreate(aliceDataSource
, &error
), "create alice engine: %@", error
);
199 CFReleaseNull(error
);
200 CFStringRef bobID
= CFStringCreateWithFormat(kCFAllocatorDefault
, 0, CFSTR("Bob-%s"), name
);
202 __block CFDataRef queued_message
= NULL
;
204 SOSPeerSendBlock enqueueMessage
= ^bool (CFDataRef message
, CFErrorRef
*error
) {
206 fail("We already had an unproccessed message");
208 queued_message
= (CFDataRef
) CFRetain(message
);
212 CFDataRef (^dequeueMessage
)() = ^CFDataRef () {
213 CFDataRef result
= queued_message
;
214 queued_message
= NULL
;
220 ok(bobPeer
= SOSPeerCreateSimple(bobID
, kSOSPeerVersion
, &error
, enqueueMessage
),
221 "create peer: %@", error
);
223 /* Setup Bob engine, dataSource and peer for Bob to talk to Alice */
224 SOSDataSourceRef bobDataSource
= SOSTestDataSourceCreate();
225 SOSEngineRef bobEngine
;
226 ok(bobEngine
= SOSEngineCreate(bobDataSource
, &error
), "create bob engine: %@", error
);
227 CFReleaseNull(error
);
228 CFStringRef aliceID
= CFStringCreateWithFormat(kCFAllocatorDefault
, 0, CFSTR("Alice-%s"), name
);
230 SOSPeerRef alicePeer
;
231 ok(alicePeer
= SOSPeerCreateSimple(aliceID
, kSOSPeerVersion
, &error
, enqueueMessage
),
232 "create peer: %@", error
);
233 CFReleaseNull(error
);
235 /* Now call provided setup blocks to populate the dataSources with
236 interesting stuff. */
237 aliceInit(aliceDataSource
);
238 bobInit(bobDataSource
);
248 message
= dequeueMessage();
250 /* We are expecting a message and msg is it's digest. */
252 CFStringRef messageDigestStr
= SOSMessageCopyDigestHex(message
);
254 bool handeled
= SOSEngineHandleMessage(alice
? aliceEngine
: bobEngine
, alice
? bobPeer
: alicePeer
, message
, &error
);
255 if (!CFEqual(messageDigestStr
, msg
)) {
257 fail("%s %s received message [%d] digest %@ != %@ %@", name
, alice
? "Alice" : "Bob", msg_index
, messageDigestStr
, msg
, message
);
259 fail("%s %s failed to handle message [%d] digest %@ != %@ %@: %@", name
, alice
? "Alice" : "Bob", msg_index
, messageDigestStr
, msg
, message
, error
);
260 CFReleaseNull(error
);
262 } else if (handeled
) {
263 pass("%s %s handled message [%d] %@", name
, alice
? "Alice" : "Bob", msg_index
, message
);
265 fail("%s %s failed to handle message [%d] %@: %@", name
, alice
? "Alice" : "Bob", msg_index
, message
, error
);
266 CFReleaseNull(error
);
269 fail("%s %s sent extra message [%d] with digest %@: %@", name
, alice
? "Bob" : "Alice", msg_index
, messageDigestStr
, message
);
271 CFRelease(messageDigestStr
);
275 fail("%s %s expected message [%d] with digest %@, none received", name
, alice
? "Alice" : "Bob", msg_index
, msg
);
277 /* Compare alice and bobs dataSources databases. */
278 ok(CFEqual(SOSTestDataSourceGetDatabase(aliceDataSource
), SOSTestDataSourceGetDatabase(bobDataSource
)), "%s Alice and Bob are in sync", name
);
284 msg
= va_arg(msgs
, CFStringRef
);
294 SOSEngineDispose(aliceEngine
); // Also disposes aliceDataSource
295 CFReleaseSafe(alicePeer
);
296 CFReleaseSafe(aliceID
);
298 SOSEngineDispose(bobEngine
); // Also disposes bobDataSource
299 CFReleaseSafe(bobPeer
);
300 CFReleaseSafe(bobID
);
304 static void synctests(void) {
305 // Sync between 2 empty dataSources
307 ^ (SOSDataSourceRef dataSource
) {},
308 ^ (SOSDataSourceRef dataSource
) {},
309 CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"),
310 CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"),
311 CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"),
314 // Sync a dataSource with one object to an empty dataSource
316 ^ (SOSDataSourceRef dataSource
) {
317 CFErrorRef error
= NULL
;
318 SOSObjectRef object
= SOSDataSourceCreateGenericItem(dataSource
, CFSTR("test_account"), CFSTR("test service"));
319 ok(dataSource
->add(dataSource
, object
, &error
), "dataSource added object %@", error
);
320 CFReleaseSafe(object
);
321 CFReleaseNull(error
);
323 ^ (SOSDataSourceRef dataSource
) {},
324 CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"),
325 CFSTR("147B6C509908CC4A9FC4263973A842104A64CE01"),
326 CFSTR("019B494F3C06B48BB02C280AF1E19AD861A7003C"),
327 CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"),
330 // Sync a dataSource with one object to another dataSource with the same object
331 testsync("alice1bob1",
332 ^ (SOSDataSourceRef dataSource
) {
333 CFErrorRef error
= NULL
;
334 SOSObjectRef object
= SOSDataSourceCreateGenericItem(dataSource
, CFSTR("test_account"), CFSTR("test service"));
335 ok(dataSource
->add(dataSource
, object
, &error
), "dataSource added object %@", error
);
336 CFReleaseSafe(object
);
337 CFReleaseNull(error
);
339 ^ (SOSDataSourceRef dataSource
) {
340 CFErrorRef error
= NULL
;
341 SOSObjectRef object
= SOSDataSourceCreateGenericItem(dataSource
, CFSTR("test_account"), CFSTR("test service"));
342 ok(dataSource
->add(dataSource
, object
, &error
), "dataSource added object %@", error
);
343 CFReleaseSafe(object
);
344 CFReleaseNull(error
);
346 CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"),
347 CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"),
348 CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"),
351 // Sync a dataSource with one object to another dataSource with the same object
352 testsync("alice1bob2",
353 ^ (SOSDataSourceRef dataSource
) {
354 CFErrorRef error
= NULL
;
355 SOSObjectRef object
= SOSDataSourceCreateGenericItem(dataSource
, CFSTR("test_account"), CFSTR("test service"));
356 ok(dataSource
->add(dataSource
, object
, &error
), "dataSource added object %@", error
);
357 CFReleaseSafe(object
);
358 CFReleaseNull(error
);
360 ^ (SOSDataSourceRef dataSource
) {
361 CFErrorRef error
= NULL
;
362 SOSObjectRef object
= SOSDataSourceCreateGenericItem(dataSource
, CFSTR("test_account"), CFSTR("test service"));
363 ok(dataSource
->add(dataSource
, object
, &error
), "dataSource added object %@", error
);
364 CFReleaseSafe(object
);
365 object
= SOSDataSourceCreateGenericItem(dataSource
, CFSTR("account1"), CFSTR("service1"));
366 ok(dataSource
->add(dataSource
, object
, &error
), "dataSource added object %@", error
);
367 CFReleaseSafe(object
);
368 CFReleaseNull(error
);
370 CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"),
371 CFSTR("D4049A1063CFBF7CAF8424E13DE3CE926FF5856C"),
372 CFSTR("9624EA855BBED6B668868BB723443E804D04F6A1"),
373 CFSTR("063E097CCD4FEB7F3610ED12B3DA828467314846"),
374 CFSTR("D1B3944E3084425F41B2C2EA0BE82170E10AA37D"),
382 int sc_70_engine(int argc
, char *const *argv
)
384 plan_tests(kTestTestCount
);
388 //testsync(NULL, NULL, NULL, NULL);