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