]> git.saurik.com Git - apple/security.git/blob - sec/SOSCircle/Regressions/sc-70-engine.c
Security-55471.14.8.tar.gz
[apple/security.git] / sec / SOSCircle / Regressions / sc-70-engine.c
1 //
2 // sc-70-engine.c
3 // sec
4 //
5 // Created by Michael Brouwer on 8/2/12.
6 // Copyright 2012 Apple Inc. All rights reserved.
7 //
8 //
9
10 #include <SecureObjectSync/SOSEngine.h>
11 #include <SecureObjectSync/SOSPeer.h>
12
13 #include "SOSCircle_regressions.h"
14
15 #include <corecrypto/ccsha2.h>
16 #include <Security/SecBase64.h>
17
18 #include <utilities/SecCFWrappers.h>
19
20 #include <stdint.h>
21 #include "SOSTestDataSource.h"
22 #include "SOSTestTransport.h"
23
24 static int kTestTestCount = 61;
25
26 static void tests(void)
27 {
28 CFErrorRef error = NULL;
29
30 /* Transport. */
31 __block unsigned msg_count = 0;
32 uint8_t msg_digest_buffer[CCSHA256_OUTPUT_SIZE];
33 uint8_t *msg_digest = msg_digest_buffer;
34
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) {
40 /* message n=0 */
41 ccdigest(sha256, msglen, msg, msg_digest);
42 } else {
43 /* message n=n+1 */
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);
49 }
50 size_t encmaxlen = SecBase64Encode(msg, msglen, NULL, 0);
51 CFMutableDataRef encoded = CFDataCreateMutable(NULL, encmaxlen);
52 CFDataSetLength(encoded, encmaxlen);
53 SecBase64Result rc;
54 char *enc = (char *)CFDataGetMutableBytePtr(encoded);
55 #ifndef NDEBUG
56 size_t enclen =
57 #endif
58 SecBase64Encode2(msg, msglen,
59 enc,
60 encmaxlen, kSecB64_F_LINE_LEN_USE_PARAM,
61 64, &rc);
62 assert(enclen < INT32_MAX);
63 // printf("=== BEGIN SOSMESSAGE ===\n%.*s\n=== END SOSMESSAGE ===\n", (int)enclen, enc);
64 CFRelease(encoded);
65 return true;
66 };
67
68 /* Create peer test. */
69 CFStringRef peer_id = CFSTR("peer 70");
70 SOSPeerRef peer;
71 ok(peer = SOSPeerCreateSimple(peer_id, kSOSPeerVersion, &error, sendBlock),
72 "create peer: %@", error);
73 CFReleaseNull(error);
74
75 /* DataSource */
76 SOSDataSourceRef ds = SOSTestDataSourceCreate();
77
78 /* Create engine test. */
79 SOSEngineRef engine;
80 ok(engine = SOSEngineCreate(ds, &error), "create engine: %@", error);
81 CFReleaseNull(error);
82
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);
87
88 /* Test passing peer messages to the engine. */
89 CFDataRef message;
90
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);
95 CFReleaseNull(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);
100
101
102 /* Create manifest digest message. */
103 SKIP: {
104 skip("Create manifest digest message failed", 2,
105 ok(message = SOSEngineCreateManifestDigestMessage(engine, peer,
106 &error),
107 "create manifest digest message: %@", error));
108 CFReleaseNull(error);
109 /* Pass manifest digest message to the engine for handeling. */
110 skip("", 1,
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);
117 }
118 CFReleaseNull(message);
119 CFReleaseNull(error);
120
121 /* Create manifest message. */
122 SKIP: {
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. */
128 skip("", 1,
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);
135 }
136 CFReleaseNull(message);
137 CFReleaseNull(error);
138
139 /* Create manifest and objects message. */
140 SKIP: {
141 skip("Create manifest and objects message failed", 2,
142 ok(message = SOSEngineCreateManifestAndObjectsMessage(engine, peer,
143 &error),
144 "create manifest and objects message: %@", error));
145 CFReleaseNull(error);
146 /* Pass manifest and objects message to the engine for handeling. */
147 skip("", 1,
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);
154 }
155 CFReleaseNull(message);
156 CFReleaseNull(error);
157
158 /* Clean up. */
159 SOSPeerDispose(peer);
160 SOSEngineDispose(engine);
161 }
162
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]);
169 }
170 return hex;
171 }
172
173 static void testsync(const char *name, void (^aliceInit)(SOSDataSourceRef ds), void (^bobInit)(SOSDataSourceRef ds), CFStringRef msg, ...) {
174 CFErrorRef error = NULL;
175
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);
182
183 __block CFDataRef queued_message = NULL;
184
185 SOSPeerSendBlock enqueueMessage = ^bool (CFDataRef message, CFErrorRef *error) {
186 if (queued_message)
187 fail("We already had an unproccessed message");
188
189 queued_message = (CFDataRef) CFRetain(message);
190 return true;
191 };
192
193 CFDataRef (^dequeueMessage)() = ^CFDataRef () {
194 CFDataRef result = queued_message;
195 queued_message = NULL;
196
197 return result;
198 };
199
200 SOSPeerRef bobPeer;
201 ok(bobPeer = SOSPeerCreateSimple(bobID, kSOSPeerVersion, &error, enqueueMessage),
202 "create peer: %@", error);
203
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);
210
211 SOSPeerRef alicePeer;
212 ok(alicePeer = SOSPeerCreateSimple(aliceID, kSOSPeerVersion, &error, enqueueMessage),
213 "create peer: %@", error);
214 CFReleaseNull(error);
215
216 /* Now call provided setup blocks to populate the dataSources with
217 interesting stuff. */
218 aliceInit(aliceDataSource);
219 bobInit(bobDataSource);
220
221 /* Start syncing by making alice send the first message. */
222 ok(SOSEngineSyncWithPeer(aliceEngine, bobPeer, false, &error), "tell Alice sync with peer Bob");
223 CFDataRef message;
224
225 va_list msgs;
226 va_start(msgs, msg);
227
228 int msg_index = 0;
229 bool alice = false;
230 for (;;) {
231 message = dequeueMessage();
232 msg_index++;
233 /* We are expecting a message and msg is it's digest. */
234 if (message) {
235 CFStringRef messageDesc = SOSMessageCopyDescription(message);
236 CFStringRef messageDigestStr = SOSMessageCopyDigestHex(message);
237 if (msg) {
238 bool handeled = SOSEngineHandleMessage(alice ? aliceEngine : bobEngine, alice ? bobPeer : alicePeer, message, &error);
239 if (!CFEqual(messageDigestStr, msg)) {
240 if (handeled) {
241 fail("%s %s received message [%d] digest %@ != %@ %@", name, alice ? "Alice" : "Bob", msg_index, messageDigestStr, msg, messageDesc);
242 } else {
243 fail("%s %s failed to handle message [%d] digest %@ != %@ %@: %@", name, alice ? "Alice" : "Bob", msg_index, messageDigestStr, msg, messageDesc, error);
244 CFReleaseNull(error);
245 }
246 } else if (handeled) {
247 pass("%s %s handled message [%d] %@", name, alice ? "Alice" : "Bob", msg_index, messageDesc);
248 } else {
249 fail("%s %s failed to handle message [%d] %@: %@", name, alice ? "Alice" : "Bob", msg_index, messageDesc, error);
250 CFReleaseNull(error);
251 }
252 } else {
253 fail("%s %s sent extra message [%d] with digest %@: %@", name, alice ? "Bob" : "Alice", msg_index, messageDigestStr, messageDesc);
254 }
255 CFRelease(messageDigestStr);
256 CFRelease(messageDesc);
257 CFRelease(message);
258 } else {
259 if (msg) {
260 fail("%s %s expected message [%d] with digest %@, none received", name, alice ? "Alice" : "Bob", msg_index, msg);
261 } else {
262 /* Compare alice and bobs dataSources databases. */
263 ok(CFEqual(SOSTestDataSourceGetDatabase(aliceDataSource), SOSTestDataSourceGetDatabase(bobDataSource)), "%s Alice and Bob are in sync", name);
264 }
265 }
266
267 if (msg) {
268 alice = !alice;
269 msg = va_arg(msgs, CFStringRef);
270 } else
271 break;
272 }
273
274 va_end(msgs);
275
276 SOSEngineDispose(aliceEngine); // Also disposes aliceDataSource
277 SOSPeerDispose(alicePeer);
278 CFReleaseSafe(aliceID);
279
280 SOSEngineDispose(bobEngine); // Also disposes bobDataSource
281 SOSPeerDispose(bobPeer);
282 CFReleaseSafe(bobID);
283 }
284
285 static void synctests(void) {
286 // Sync between 2 empty dataSources
287 testsync("empty",
288 ^ (SOSDataSourceRef dataSource) {},
289 ^ (SOSDataSourceRef dataSource) {},
290 CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"),
291 CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"),
292 CFSTR("2AF312E092D67308A0083DFFBF2B6B754B967864"),
293 NULL);
294
295 // Sync a dataSource with one object to an empty dataSource
296 testsync("alice1",
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);
303 },
304 ^ (SOSDataSourceRef dataSource) {},
305 CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"),
306 CFSTR("147B6C509908CC4A9FC4263973A842104A64CE01"),
307 CFSTR("019B494F3C06B48BB02C280AF1E19AD861A7003C"),
308 CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"),
309 NULL);
310
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);
319 },
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);
326 },
327 CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"),
328 CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"),
329 CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"),
330 NULL);
331
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);
340 },
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);
350 },
351 CFSTR("ADAA3ACE75ED516CB91893413EE9CC9ED04CA47B"),
352 CFSTR("D4049A1063CFBF7CAF8424E13DE3CE926FF5856C"),
353 CFSTR("9624EA855BBED6B668868BB723443E804D04F6A1"),
354 CFSTR("063E097CCD4FEB7F3610ED12B3DA828467314846"),
355 CFSTR("D1B3944E3084425F41B2C2EA0BE82170E10AA37D"),
356 NULL);
357
358 }
359
360 int sc_70_engine(int argc, char *const *argv)
361 {
362 plan_tests(kTestTestCount);
363
364 tests();
365 synctests();
366
367 return 0;
368 }