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@
27 // /AppleInternal/Applications/SecurityTests.app/SecurityTests sc_kvstool -v -- --dump
28 // /AppleInternal/Applications/SecurityTests.app/SecurityTests sc_kvstool -v -- --clear
29 // /AppleInternal/Applications/SecurityTests.app/SecurityTests sc_kvstool -v -- --putcircle
30 // /AppleInternal/Applications/SecurityTests.app/SecurityTests sc_kvstool -v -- --direct --dump
31 // /AppleInternal/Applications/SecurityTests.app/SecurityTests sc_kvstool -v -- --direct --putcircle
33 #include <Foundation/Foundation.h>
34 #include <SecureObjectSync/SOSEngine.h>
35 #include <SecureObjectSync/SOSPeer.h>
36 #include <SecureObjectSync/SOSInternal.h>
37 #include <SecureObjectSync/SOSCloudCircle.h>
39 #include "SOSCircle_regressions.h"
41 #include <corecrypto/ccsha2.h>
43 #include <utilities/SecCFWrappers.h>
44 #include <utilities/debugging.h>
48 #include <AssertMacros.h>
53 #include <CoreFoundation/CFDate.h>
57 #include <dispatch/dispatch.h>
59 #include "SOSCircle_regressions.h"
60 #include "CKDLocalKeyValueStore.h"
61 #include "SOSRegressionUtilities.h"
62 #include "SOSTestDataSource.h"
63 #include "SOSTestTransport.h"
64 #include "SOSCloudKeychainClient.h"
66 #import "SOSDirectCloudTransport.h"
68 // MARK: ----- Constants -----
70 static CFStringRef circleKey = CFSTR("Circle");
72 // MARK: ----- start of all tests -----
74 static void putCircleInCloud(SOSCircleRef circle, dispatch_queue_t work_queue, dispatch_group_t work_group)
76 CFErrorRef error = NULL;
77 CFDataRef newCloudCircleEncoded = SOSCircleCopyEncodedData(circle, kCFAllocatorDefault, &error);
78 ok(newCloudCircleEncoded, "Encoded as: %@ [%@]", newCloudCircleEncoded, error);
80 // Send the circle with our application request back to cloud
81 testPutObjectInCloud(circleKey, newCloudCircleEncoded, &error, work_group, work_queue);
84 static void createAndPutInitialCircle(void)
86 dispatch_queue_t work_queue = dispatch_queue_create("capic", DISPATCH_QUEUE_CONCURRENT);
87 dispatch_group_t work_group = dispatch_group_create();
89 CFErrorRef error = NULL;
90 CFStringRef cflabel = CFSTR("TEST_USERKEY");
91 CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10);
92 SOSCCRegisterUserCredentials(cflabel, cfpassword, &error);
94 CFErrorRef localError = NULL;
96 SOSDataSourceFactoryRef our_data_source_factory = SOSTestDataSourceFactoryCreate();
97 SOSDataSourceRef our_data_source = SOSTestDataSourceCreate();
98 SOSTestDataSourceFactoryAddDataSource(our_data_source_factory, circleKey, our_data_source);
100 CFDictionaryRef gestalt = SOSCreatePeerGestaltFromName(CFSTR("Alice"));
102 SOSAccountRef our_account = SOSAccountCreate(kCFAllocatorDefault, gestalt, our_data_source_factory,
105 pass("SOSAccountKeyInterestBlock");
107 ^ bool (CFDictionaryRef keys, CFErrorRef *error)
109 pass("SOSAccountDataUpdateBlock");
113 SOSAccountEnsureCircle(our_account, circleKey);
115 SOSFullPeerInfoRef our_full_peer_info = SOSAccountGetMyFullPeerInCircleNamed(our_account, circleKey, &error);
116 SOSPeerInfoRef our_peer_info = SOSFullPeerInfoGetPeerInfo(our_full_peer_info);
117 CFRetain(our_peer_info);
119 SOSCircleRef circle = SOSAccountFindCircle(our_account, circleKey);
122 // SecKeyRef user_privkey = SOSUserGetPrivKey(&localError);
123 SecKeyRef user_privkey = NULL; // TODO: this will not work
124 ok(SOSCircleRequestAdmission(circle, user_privkey, our_full_peer_info, &localError), "Requested admission (%@)", our_peer_info);
125 ok(SOSCircleAcceptRequests(circle, user_privkey, our_full_peer_info, &localError), "Accepted self");
127 putCircleInCloud(circle, work_queue, work_group);
128 pass("Put circle in cloud: (%@)", circle);
133 static void postCircleChangeNotification()
135 NSArray *keys = [NSArray arrayWithObjects:(id)circleKey, nil];
136 NSDictionary* userInfo = [[NSDictionary alloc] initWithObjectsAndKeys:
137 keys, NSUbiquitousKeyValueStoreChangedKeysKey,
138 [NSNumber numberWithInt:NSUbiquitousKeyValueStoreServerChange], NSUbiquitousKeyValueStoreChangeReasonKey,
140 [[NSNotificationCenter defaultCenter] postNotificationName:NSUbiquitousKeyValueStoreDidChangeExternallyNotification object:NULL userInfo:userInfo];
144 static void requestSynchronization(dispatch_queue_t processQueue, dispatch_group_t dgroup)
146 testSynchronize(processQueue, dgroup);
149 static void displayCircles(CFTypeRef objects)
151 // SOSCCCopyApplicantPeerInfo doesn't display all info, e.g. in the case where we are not in circle
152 CFDictionaryForEach(objects, ^(const void *key, const void *value)
154 if (SOSKVSKeyGetKeyType(key) == kCircleKey)
156 CFErrorRef localError = NULL;
159 SOSCircleRef circle = SOSCircleCreateFromData(NULL, (CFDataRef) value, &localError);
160 pass("circle: %@ %@", key, circle);
161 CFReleaseSafe(circle);
164 pass("non-circle: %@ %@", key, value);
170 static void dumpCircleInfo()
172 CFErrorRef error = NULL;
173 CFArrayRef applicantPeerInfos = NULL;
174 CFArrayRef peerInfos = NULL;
177 NSArray *ccmsgs = @[@"Error", @"InCircle", @"NotInCircle", @"RequestPending", @"CircleAbsent"];
179 SOSCCStatus ccstatus = SOSCCThisDeviceIsInCircle(&error);
180 pass("ccstatus: %d, error: %@", ccstatus, error);
181 idx = ccstatus-kSOSCCError;
182 if (0<=idx && idx<(int)[ccmsgs count])
183 pass("ccstatus: %d (%@)", ccstatus, ccmsgs[idx]);
185 // Now look at current applicants
186 applicantPeerInfos = SOSCCCopyApplicantPeerInfo(&error);
187 if (applicantPeerInfos)
189 pass("Applicants: %ld, error: %@", (long)CFArrayGetCount(applicantPeerInfos), error);
190 CFArrayForEach(applicantPeerInfos, ^(const void *value) {
191 SOSPeerInfoRef peer = (SOSPeerInfoRef)value;
192 CFStringRef peerName = SOSPeerInfoGetPeerName(peer);
193 pass("Applicant: %@", peerName);
197 pass("No applicants, error: %@", error);
200 peerInfos = SOSCCCopyPeerPeerInfo(&error);
203 pass("Peers: %ld, error: %@", (long)CFArrayGetCount(applicantPeerInfos), error);
204 CFArrayForEach(peerInfos, ^(const void *value) {
205 SOSPeerInfoRef peer = (SOSPeerInfoRef)value;
206 CFStringRef peerName = SOSPeerInfoGetPeerName(peer);
207 pass("Peer: %@", peerName);
211 pass("No peers, error: %@", error);
214 // define the options table for the command line
215 static const struct option options[] =
217 { "verbose", optional_argument, NULL, 'v' },
218 { "dump", optional_argument, NULL, 'd' },
219 { "clear", optional_argument, NULL, 'C' },
220 { "putcircle", optional_argument, NULL, 'p' },
221 { "direct", optional_argument, NULL, 'D' },
222 { "notify", optional_argument, NULL, 'n' },
223 { "sync", optional_argument, NULL, 's' },
224 { "info", optional_argument, NULL, 'i' },
228 static int kTestCount = 10;
230 static void usage(void)
233 printf(" --dump [itemName] Dump the contents of the kvs store (through proxy)\n");
234 printf(" --clear Clear the contents of the kvs store (through proxy)\n");
235 printf(" --putcircle Put a new circle into the kvs store (through proxy)\n");
236 printf(" --direct Go directly to KVS (bypass proxy)\n");
237 printf(" --notify Post a notification that the circle key has changed\n");
238 printf(" --sync Post a notification that the circle key has changed\n");
239 printf(" --info Dump info about circle and peer status\n");
246 kCommandPutCircle = 3,
248 kCommandSynchronize = 5,
253 static int command = kCommandHelp;
254 static bool useDirect = false;
256 static void tests(const char *itemName)
258 dispatch_queue_t generalq = dispatch_queue_create("general", DISPATCH_QUEUE_SERIAL);
259 dispatch_group_t work_group = dispatch_group_create();
264 SOSCloudKeychainServerInit();
267 SOSCloudKeychainSetCallbackMethodXPC(); // call this first
269 pass("Command: %d", command);
273 ok(testClearAll(generalq, work_group), "test Clear All");
277 CFArrayRef keysToGet = NULL;
280 CFStringRef itemStr = CFStringCreateWithCString(kCFAllocatorDefault, itemName, kCFStringEncodingUTF8);
281 pass("Retrieving : %@", itemStr);
282 keysToGet = CFArrayCreateForCFTypes(kCFAllocatorDefault, itemStr);
283 CFReleaseSafe(itemStr);
285 CFTypeRef objects = testGetObjectsFromCloud(keysToGet, generalq, work_group);
286 CFReleaseSafe(keysToGet);
287 pass(" : %@", objects);
288 displayCircles(objects);
291 case kCommandPutCircle:
292 createAndPutInitialCircle();
295 postCircleChangeNotification();
297 case kCommandSynchronize:
298 requestSynchronization(generalq, work_group);
310 int sc_kvstool(int argc, char *const *argv)
312 char *itemName = NULL;
313 // extern int optind;
317 while (argSlot = -1, (arg = getopt_long(argc, (char * const *)argv, "ivChpdns", options, &argSlot)) != -1)
321 itemName = (char *)(optarg);
322 command = kCommandDump;
324 case 'C': // should set up to call testClearAll
325 command = kCommandClear;
328 command = kCommandPutCircle;
331 command = kCommandNotify;
334 command = kCommandSynchronize;
337 command = kCommandInfo;
341 printf("Using direct calls to KVS\n");
344 secerror("arg: %s", optarg);
348 plan_tests(kTestCount);
350 secerror("Command: %d", command);
351 printf("Command: %d\n", command);