5 // Created by John Hurley 11/01/12.
6 // Copyright 2012 Apple Inc. All rights reserved.
11 // /AppleInternal/Applications/SecurityTests.app/SecurityTests sc_kvstool -v -- --dump
12 // /AppleInternal/Applications/SecurityTests.app/SecurityTests sc_kvstool -v -- --clear
13 // /AppleInternal/Applications/SecurityTests.app/SecurityTests sc_kvstool -v -- --putcircle
14 // /AppleInternal/Applications/SecurityTests.app/SecurityTests sc_kvstool -v -- --direct --dump
15 // /AppleInternal/Applications/SecurityTests.app/SecurityTests sc_kvstool -v -- --direct --putcircle
17 #include <Foundation/Foundation.h>
18 #include <SecureObjectSync/SOSEngine.h>
19 #include <SecureObjectSync/SOSPeer.h>
20 #include <SecureObjectSync/SOSInternal.h>
21 #include <SecureObjectSync/SOSCloudCircle.h>
23 #include "SOSCircle_regressions.h"
25 #include <corecrypto/ccsha2.h>
27 #include <utilities/SecCFWrappers.h>
28 #include <utilities/debugging.h>
32 #include <AssertMacros.h>
37 #include <CoreFoundation/CFDate.h>
41 #include <dispatch/dispatch.h>
43 #include "SOSCircle_regressions.h"
44 #include "CKDLocalKeyValueStore.h"
45 #include "SOSRegressionUtilities.h"
46 #include "SOSTestDataSource.h"
47 #include "SOSTestTransport.h"
48 #include "SOSCloudKeychainClient.h"
50 #import "SOSDirectCloudTransport.h"
52 // MARK: ----- Constants -----
54 static CFStringRef circleKey = CFSTR("Circle");
56 // MARK: ----- start of all tests -----
58 static void putCircleInCloud(SOSCircleRef circle, dispatch_queue_t work_queue, dispatch_group_t work_group)
60 CFErrorRef error = NULL;
61 CFDataRef newCloudCircleEncoded = SOSCircleCopyEncodedData(circle, kCFAllocatorDefault, &error);
62 ok(newCloudCircleEncoded, "Encoded as: %@ [%@]", newCloudCircleEncoded, error);
64 // Send the circle with our application request back to cloud
65 testPutObjectInCloud(circleKey, newCloudCircleEncoded, &error, work_group, work_queue);
68 static void createAndPutInitialCircle(void)
70 dispatch_queue_t work_queue = dispatch_queue_create("capic", DISPATCH_QUEUE_CONCURRENT);
71 dispatch_group_t work_group = dispatch_group_create();
73 CFErrorRef error = NULL;
74 CFStringRef cflabel = CFSTR("TEST_USERKEY");
75 CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10);
76 SOSCCRegisterUserCredentials(cflabel, cfpassword, &error);
78 CFErrorRef localError = NULL;
80 SOSDataSourceFactoryRef our_data_source_factory = SOSTestDataSourceFactoryCreate();
81 SOSDataSourceRef our_data_source = SOSTestDataSourceCreate();
82 SOSTestDataSourceFactoryAddDataSource(our_data_source_factory, circleKey, our_data_source);
84 CFDictionaryRef gestalt = SOSCreatePeerGestaltFromName(CFSTR("Alice"));
86 SOSAccountRef our_account = SOSAccountCreate(kCFAllocatorDefault, gestalt, our_data_source_factory,
89 pass("SOSAccountKeyInterestBlock");
91 ^ bool (CFDictionaryRef keys, CFErrorRef *error)
93 pass("SOSAccountDataUpdateBlock");
97 SOSAccountEnsureCircle(our_account, circleKey);
99 SOSFullPeerInfoRef our_full_peer_info = SOSAccountGetMyFullPeerInCircleNamed(our_account, circleKey, &error);
100 SOSPeerInfoRef our_peer_info = SOSFullPeerInfoGetPeerInfo(our_full_peer_info);
101 CFRetain(our_peer_info);
103 SOSCircleRef circle = SOSAccountFindCircle(our_account, circleKey);
106 // SecKeyRef user_privkey = SOSUserGetPrivKey(&localError);
107 SecKeyRef user_privkey = NULL; // TODO: this will not work
108 ok(SOSCircleRequestAdmission(circle, user_privkey, our_full_peer_info, &localError), "Requested admission (%@)", our_peer_info);
109 ok(SOSCircleAcceptRequests(circle, user_privkey, our_full_peer_info, &localError), "Accepted self");
111 putCircleInCloud(circle, work_queue, work_group);
112 pass("Put circle in cloud: (%@)", circle);
117 static void postCircleChangeNotification()
119 NSArray *keys = [NSArray arrayWithObjects:(id)circleKey, nil];
120 NSDictionary* userInfo = [[NSDictionary alloc] initWithObjectsAndKeys:
121 keys, NSUbiquitousKeyValueStoreChangedKeysKey,
122 [NSNumber numberWithInt:NSUbiquitousKeyValueStoreServerChange], NSUbiquitousKeyValueStoreChangeReasonKey,
124 [[NSNotificationCenter defaultCenter] postNotificationName:NSUbiquitousKeyValueStoreDidChangeExternallyNotification object:NULL userInfo:userInfo];
128 static void requestSynchronization(dispatch_queue_t processQueue, dispatch_group_t dgroup)
130 testSynchronize(processQueue, dgroup);
133 static void displayCircles(CFTypeRef objects)
135 // SOSCCCopyApplicantPeerInfo doesn't display all info, e.g. in the case where we are not in circle
136 CFDictionaryForEach(objects, ^(const void *key, const void *value)
138 if (SOSKVSKeyGetKeyType(key) == kCircleKey)
140 CFErrorRef localError = NULL;
143 SOSCircleRef circle = SOSCircleCreateFromData(NULL, (CFDataRef) value, &localError);
144 pass("circle: %@ %@", key, circle);
145 CFReleaseSafe(circle);
148 pass("non-circle: %@ %@", key, value);
154 static void dumpCircleInfo()
156 CFErrorRef error = NULL;
157 CFArrayRef applicantPeerInfos = NULL;
158 CFArrayRef peerInfos = NULL;
161 NSArray *ccmsgs = @[@"ParamErr", @"Error", @"InCircle", @"NotInCircle", @"RequestPending", @"CircleAbsent" ];
163 SOSCCStatus ccstatus = SOSCCThisDeviceIsInCircle(&error);
164 pass("ccstatus: %d, error: %@", ccstatus, error);
165 idx = ccstatus-kSOSCCParamErr;
166 if (0<=idx && idx<(int)[ccmsgs count])
167 pass("ccstatus: %d (%@)", ccstatus, ccmsgs[idx]);
169 // Now look at current applicants
170 applicantPeerInfos = SOSCCCopyApplicantPeerInfo(&error);
171 if (applicantPeerInfos)
173 pass("Applicants: %ld, error: %@", (long)CFArrayGetCount(applicantPeerInfos), error);
174 CFArrayForEach(applicantPeerInfos, ^(const void *value) {
175 SOSPeerInfoRef peer = (SOSPeerInfoRef)value;
176 CFStringRef peerName = SOSPeerInfoGetPeerName(peer);
177 pass("Applicant: %@", peerName);
181 pass("No applicants, error: %@", error);
184 peerInfos = SOSCCCopyPeerPeerInfo(&error);
187 pass("Peers: %ld, error: %@", (long)CFArrayGetCount(applicantPeerInfos), error);
188 CFArrayForEach(peerInfos, ^(const void *value) {
189 SOSPeerInfoRef peer = (SOSPeerInfoRef)value;
190 CFStringRef peerName = SOSPeerInfoGetPeerName(peer);
191 pass("Peer: %@", peerName);
195 pass("No peers, error: %@", error);
198 // define the options table for the command line
199 static const struct option options[] =
201 { "verbose", optional_argument, NULL, 'v' },
202 { "dump", optional_argument, NULL, 'd' },
203 { "clear", optional_argument, NULL, 'C' },
204 { "putcircle", optional_argument, NULL, 'p' },
205 { "direct", optional_argument, NULL, 'D' },
206 { "notify", optional_argument, NULL, 'n' },
207 { "sync", optional_argument, NULL, 's' },
208 { "info", optional_argument, NULL, 'i' },
212 static int kTestCount = 10;
214 static void usage(void)
217 printf(" --dump [itemName] Dump the contents of the kvs store (through proxy)\n");
218 printf(" --clear Clear the contents of the kvs store (through proxy)\n");
219 printf(" --putcircle Put a new circle into the kvs store (through proxy)\n");
220 printf(" --direct Go directly to KVS (bypass proxy)\n");
221 printf(" --notify Post a notification that the circle key has changed\n");
222 printf(" --sync Post a notification that the circle key has changed\n");
223 printf(" --info Dump info about circle and peer status\n");
230 kCommandPutCircle = 3,
232 kCommandSynchronize = 5,
237 static int command = kCommandHelp;
238 static bool useDirect = false;
240 static void tests(const char *itemName)
242 dispatch_queue_t generalq = dispatch_queue_create("general", DISPATCH_QUEUE_SERIAL);
243 dispatch_group_t work_group = dispatch_group_create();
248 SOSCloudKeychainServerInit();
251 SOSCloudKeychainSetCallbackMethodXPC(); // call this first
253 pass("Command: %d", command);
257 ok(testClearAll(generalq, work_group), "test Clear All");
261 CFArrayRef keysToGet = NULL;
264 CFStringRef itemStr = CFStringCreateWithCString(kCFAllocatorDefault, itemName, kCFStringEncodingUTF8);
265 pass("Retrieving : %@", itemStr);
266 keysToGet = CFArrayCreateForCFTypes(kCFAllocatorDefault, itemStr);
267 CFReleaseSafe(itemStr);
269 CFTypeRef objects = testGetObjectsFromCloud(keysToGet, generalq, work_group);
270 CFReleaseSafe(keysToGet);
271 pass(" : %@", objects);
272 displayCircles(objects);
275 case kCommandPutCircle:
276 createAndPutInitialCircle();
279 postCircleChangeNotification();
281 case kCommandSynchronize:
282 requestSynchronization(generalq, work_group);
294 int sc_kvstool(int argc, char *const *argv)
296 char *itemName = NULL;
297 // extern int optind;
301 while (argSlot = -1, (arg = getopt_long(argc, (char * const *)argv, "ivChpdns", options, &argSlot)) != -1)
305 itemName = (char *)(optarg);
306 command = kCommandDump;
308 case 'C': // should set up to call testClearAll
309 command = kCommandClear;
312 command = kCommandPutCircle;
315 command = kCommandNotify;
318 command = kCommandSynchronize;
321 command = kCommandInfo;
325 printf("Using direct calls to KVS\n");
328 secerror("arg: %s", optarg);
332 plan_tests(kTestCount);
334 secerror("Command: %d", command);
335 printf("Command: %d\n", command);