1/*
2 * Copyright (c) 2012-2014 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#include <SecureObjectSync/SOSEngine.h>
26#include <SecureObjectSync/SOSPeer.h>
27
28#include "SOSCircle_regressions.h"
29
30#include <corecrypto/ccsha2.h>
31
32#include <utilities/SecCFWrappers.h>
33
34#include <stdint.h>
35
36#include <AssertMacros.h>
37
38#include <stdio.h>
39#include <stdlib.h>
40#include <unistd.h>
41#include <CoreFoundation/CFDate.h>
42
43#include <utilities/SecCFWrappers.h>
44
45#include <Security/SecKey.h>
46
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>
55
56#include <SecureObjectSync/SOSAccountPriv.h>
57
58#include "SOSCircle_regressions.h"
59#include "SOSRegressionUtilities.h"
60#include "SOSTestDataSource.h"
61
62#include <securityd/Regressions/SOSAccountTesting.h>
63#include <securityd/Regressions/SOSTransportTestTransports.h>
64
65#ifndef SEC_CONST_DECL
66#define SEC_CONST_DECL(k,v) CFTypeRef k = (CFTypeRef)(CFSTR(v));
67#endif
68
69#include <securityd/SOSCloudCircleServer.h>
70
71
72// MARK: ----- Constants -----
73
74static CFStringRef circleKey = CFSTR("Circle");
75
76static int kTestTestCount = 68;
77
78static bool withEngine(SOSCircleRef circle, SOSDataSourceFactoryRef factory, bool readOnly, CFErrorRef *error, bool (^action)(SOSEngineRef engine, CFErrorRef *block_error)) {
79    bool success = false;
80    SOSDataSourceRef ds = NULL;
81    SOSEngineRef engine = NULL;
82
83    ds = factory->create_datasource(factory, SOSCircleGetName(circle), error);
84    require_quiet(ds, exit);
85
86    engine = SOSEngineCreate(ds, error); // Hand off DS to engine.
87    ds = NULL;
88    require_quiet(engine, exit);
89
90    success = action(engine, error);
91
92exit:
93    if (engine)
94        SOSEngineDispose(engine);
95
96    return success;
97}
98
99static bool SOSCircleSyncWithPeer(SOSAccountRef account ,SOSFullPeerInfoRef myRef, SOSCircleRef circle, SOSDataSourceFactoryRef factory,
100                           SOSPeerInfoRef peerInfo, CFErrorRef *error)
101{
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;
105
106        CFMutableDictionaryRef circleToPeerIDs = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
107        CFMutableArrayRef peer_ids = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
108        CFArrayAppendValue(peer_ids, SOSPeerGetID(peer));
109        CFDictionaryAddValue(circleToPeerIDs, SOSCircleGetName(circle), peer_ids);
110
111        SOSTransportMessageRef transport = (SOSTransportMessageRef)CFDictionaryGetValue(SOSAccountGetMessageTransports(account), SOSCircleGetName(circle));
112
113        bool result = SOSTransportMessageSyncWithPeers(transport, circleToPeerIDs, error);
114        CFReleaseSafe(peer);
115        return result;
116    });
117}
118
119static bool SOSCircleHandlePeerMessage(SOSAccountRef account, SOSCircleRef circle, SOSFullPeerInfoRef myRef, SOSDataSourceFactoryRef factory,
120                            SOSPeerInfoRef peerInfo, CFDataRef message, CFErrorRef *error) {
121
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);
129
130        CFReleaseSafe(peer);
131        CFReleaseNull(decodedMessage);
132        return result;
133    });
134}
135
136
137
138static void tests()
139{
140    CFErrorRef error = NULL;
141
142    CFStringRef aliceID = CFSTR("Alice");
143    CFStringRef bobID = CFSTR("Bob");    // not really remote, just another client on same machine
144
145    SecKeyRef alice_key = NULL;
146    SecKeyRef bob_key = NULL;
147
148    CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10);
149
150    CFDataRef parameters = SOSUserKeyCreateGenerateParameters(&error);
151    ok(parameters, "No parameters!");
152    ok(error == NULL, "Error: (%@)", error);
153    CFReleaseNull(error);
154
155    SecKeyRef user_privkey = SOSUserKeygen(cfpassword, parameters, &error);
156    CFReleaseNull(parameters);
157    CFReleaseSafe(cfpassword);
158
159    CFStringRef circleName = CFSTR("Woot Circle");
160    SOSAccountRef alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), circleName);
161    SOSAccountRef bob_account = CreateAccountForLocalChanges(CFSTR("Bob"), circleName);
162
163
164    SOSFullPeerInfoRef alice_full_peer_info = SOSCreateFullPeerInfoFromName(aliceID, &alice_key, &error);
165    SOSPeerInfoRef alice_peer_info = SOSFullPeerInfoGetPeerInfo(alice_full_peer_info);
166
167    SOSFullPeerInfoRef bob_full_peer_info = SOSCreateFullPeerInfoFromName(bobID, &bob_key, &error);
168    SOSPeerInfoRef bob_peer_info = SOSFullPeerInfoGetPeerInfo(bob_full_peer_info);
169
170    SOSCircleRef aliceCircle = SOSCircleCreate(kCFAllocatorDefault, circleName, &error);
171
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!");
176
177    alice_peer_info = SOSFullPeerInfoGetPeerInfo(alice_full_peer_info);
178    bob_peer_info = SOSFullPeerInfoGetPeerInfo(bob_full_peer_info);
179
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);
187
188    SOSTransportMessageRef alice_message_transport = (SOSTransportMessageRef)CFDictionaryGetValue(SOSAccountGetMessageTransports(alice_account), circleName);
189    SOSTransportMessageRef bob_message_transport = (SOSTransportMessageRef)CFDictionaryGetValue(bob_account->message_transports, circleName);
190
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));
193
194    SOSDataSourceFactoryRef aliceDsf = alice_account->factory;
195    SOSDataSourceFactoryRef bobDsf = bob_account->factory;
196
197    /* Test passing peer messages to the engine. */
198    CFDataRef message;
199
200    ok(SOSCircleSyncWithPeer(alice_account, alice_full_peer_info, aliceCircle, aliceDsf, bob_peer_info, &error), "Start sync [error %@]", error);
201    CFReleaseNull(error);
202
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);
209
210    is(SOSCircleSyncWithPeer(bob_account, bob_full_peer_info, bobCircle, bobDsf, alice_peer_info, &error), true, "Bob sent response");
211    CFReleaseNull(error);
212
213#if 1
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));
218
219    ok(SOSCircleHandlePeerMessage(alice_account, aliceCircle, alice_full_peer_info, aliceDsf, bob_peer_info, message, &error),
220       "Alice accepted message: %@", error);
221
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);
228#endif
229
230#if 0
231    SOSDataSourceRef aliceDs = aliceDsf->create_datasource(aliceDsf, circleName, NULL);
232    ok(CFDictionaryGetCount(SOSTransportMessageTestGetChanges((SOSTransportMessageTestRef)bob_message_transport)) == 0, "we got no message from Bob");
233
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);
238
239    ok(SOSCircleSyncWithPeer(alice_account, alice_full_peer_info, aliceCircle, aliceDsf, bob_peer_info, &error), "Restart sync [error %@]", error);
240    CFReleaseNull(error);
241
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));
246
247    is(SOSCircleHandlePeerMessage(bob_account, bobCircle, bob_full_peer_info, bobDsf, alice_peer_info, message, &error), true,
248       "bob accepted %@", message);
249    CFReleaseNull(error);
250#endif
251
252#if 1
253    bool alice = true;
254    int max_loops = 50;
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));
259        if (alice) {
260            ok(SOSCircleHandlePeerMessage(alice_account, aliceCircle, alice_full_peer_info, aliceDsf, bob_peer_info, message, &error),
261               "alice accepted %@: %@", message, error);
262        } else {
263            ok(SOSCircleHandlePeerMessage(bob_account, bobCircle, bob_full_peer_info, bobDsf, alice_peer_info, message, &error),
264               "bob accepted %@: %@", message, error);
265        }
266        alice = !alice;
267    }
268#endif
269
270    CFReleaseNull(aliceCircle);
271    CFReleaseNull(bobCircle);
272
273    CFReleaseNull(alice_peer_info);
274    CFReleaseNull(bob_peer_info);
275
276    aliceDsf->release(aliceDsf);
277    bobDsf->release(bobDsf);
278
279    SOSUnregisterAllTransportMessages();
280    SOSUnregisterAllTransportCircles();
281    SOSUnregisterAllTransportKeyParameters();
282    CFArrayRemoveAllValues(key_transports);
283    CFArrayRemoveAllValues(circle_transports);
284    CFArrayRemoveAllValues(message_transports);
285}
286
287// MARK: ----- start of all tests -----
288
289int sc_75_circle_engine(int argc, char *const *argv)
290{
291    plan_tests(kTestTestCount);
292
293    tests();
294
295	return 0;
296}
297