]> git.saurik.com Git - apple/security.git/blob - sec/SOSCircle/Regressions/sc-kvstool.m
Security-55471.14.8.tar.gz
[apple/security.git] / sec / SOSCircle / Regressions / sc-kvstool.m
1 //
2 // sc-kvstool.c
3 // sec
4 //
5 // Created by John Hurley 11/01/12.
6 // Copyright 2012 Apple Inc. All rights reserved.
7 //
8
9
10 // Run on a device:
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
16
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>
22
23 #include "SOSCircle_regressions.h"
24
25 #include <corecrypto/ccsha2.h>
26
27 #include <utilities/SecCFWrappers.h>
28 #include <utilities/debugging.h>
29
30 #include <stdint.h>
31
32 #include <AssertMacros.h>
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <CoreFoundation/CFDate.h>
38 #include <getopt.h>
39
40 #include <notify.h>
41 #include <dispatch/dispatch.h>
42
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"
49
50 #import "SOSDirectCloudTransport.h"
51
52 // MARK: ----- Constants -----
53
54 static CFStringRef circleKey = CFSTR("Circle");
55
56 // MARK: ----- start of all tests -----
57
58 static void putCircleInCloud(SOSCircleRef circle, dispatch_queue_t work_queue, dispatch_group_t work_group)
59 {
60 CFErrorRef error = NULL;
61 CFDataRef newCloudCircleEncoded = SOSCircleCopyEncodedData(circle, kCFAllocatorDefault, &error);
62 ok(newCloudCircleEncoded, "Encoded as: %@ [%@]", newCloudCircleEncoded, error);
63
64 // Send the circle with our application request back to cloud
65 testPutObjectInCloud(circleKey, newCloudCircleEncoded, &error, work_group, work_queue);
66 }
67
68 static void createAndPutInitialCircle(void)
69 {
70 dispatch_queue_t work_queue = dispatch_queue_create("capic", DISPATCH_QUEUE_CONCURRENT);
71 dispatch_group_t work_group = dispatch_group_create();
72
73 CFErrorRef error = NULL;
74 CFStringRef cflabel = CFSTR("TEST_USERKEY");
75 CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10);
76 SOSCCRegisterUserCredentials(cflabel, cfpassword, &error);
77
78 CFErrorRef localError = NULL;
79
80 SOSDataSourceFactoryRef our_data_source_factory = SOSTestDataSourceFactoryCreate();
81 SOSDataSourceRef our_data_source = SOSTestDataSourceCreate();
82 SOSTestDataSourceFactoryAddDataSource(our_data_source_factory, circleKey, our_data_source);
83
84 CFDictionaryRef gestalt = SOSCreatePeerGestaltFromName(CFSTR("Alice"));
85
86 SOSAccountRef our_account = SOSAccountCreate(kCFAllocatorDefault, gestalt, our_data_source_factory,
87 ^(CFArrayRef keys)
88 {
89 pass("SOSAccountKeyInterestBlock");
90 },
91 ^ bool (CFDictionaryRef keys, CFErrorRef *error)
92 {
93 pass("SOSAccountDataUpdateBlock");
94 return false;
95 },
96 NULL);
97 SOSAccountEnsureCircle(our_account, circleKey);
98
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);
102
103 SOSCircleRef circle = SOSAccountFindCircle(our_account, circleKey);
104 CFRetain(circle);
105
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");
110
111 putCircleInCloud(circle, work_queue, work_group);
112 pass("Put circle in cloud: (%@)", circle);
113
114 CFRelease(circle);
115 }
116
117 static void postCircleChangeNotification()
118 {
119 NSArray *keys = [NSArray arrayWithObjects:(id)circleKey, nil];
120 NSDictionary* userInfo = [[NSDictionary alloc] initWithObjectsAndKeys:
121 keys, NSUbiquitousKeyValueStoreChangedKeysKey,
122 [NSNumber numberWithInt:NSUbiquitousKeyValueStoreServerChange], NSUbiquitousKeyValueStoreChangeReasonKey,
123 nil];
124 [[NSNotificationCenter defaultCenter] postNotificationName:NSUbiquitousKeyValueStoreDidChangeExternallyNotification object:NULL userInfo:userInfo];
125 [userInfo release];
126 }
127
128 static void requestSynchronization(dispatch_queue_t processQueue, dispatch_group_t dgroup)
129 {
130 testSynchronize(processQueue, dgroup);
131 }
132
133 static void displayCircles(CFTypeRef objects)
134 {
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)
137 {
138 if (SOSKVSKeyGetKeyType(key) == kCircleKey)
139 {
140 CFErrorRef localError = NULL;
141 if (isData(value))
142 {
143 SOSCircleRef circle = SOSCircleCreateFromData(NULL, (CFDataRef) value, &localError);
144 pass("circle: %@ %@", key, circle);
145 CFReleaseSafe(circle);
146 }
147 else
148 pass("non-circle: %@ %@", key, value);
149 }
150 });
151 }
152
153
154 static void dumpCircleInfo()
155 {
156 CFErrorRef error = NULL;
157 CFArrayRef applicantPeerInfos = NULL;
158 CFArrayRef peerInfos = NULL;
159 int idx;
160
161 NSArray *ccmsgs = @[@"ParamErr", @"Error", @"InCircle", @"NotInCircle", @"RequestPending", @"CircleAbsent" ];
162
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]);
168
169 // Now look at current applicants
170 applicantPeerInfos = SOSCCCopyApplicantPeerInfo(&error);
171 if (applicantPeerInfos)
172 {
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);
178 });
179 }
180 else
181 pass("No applicants, error: %@", error);
182
183
184 peerInfos = SOSCCCopyPeerPeerInfo(&error);
185 if (peerInfos)
186 {
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);
192 });
193 }
194 else
195 pass("No peers, error: %@", error);
196 }
197
198 // define the options table for the command line
199 static const struct option options[] =
200 {
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' },
209 { }
210 };
211
212 static int kTestCount = 10;
213
214 static void usage(void)
215 {
216 printf("Usage:\n");
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");
224 }
225
226 enum kvscommands
227 {
228 kCommandClear = 1,
229 kCommandDump = 2,
230 kCommandPutCircle = 3,
231 kCommandNotify = 4,
232 kCommandSynchronize = 5,
233 kCommandInfo = 6,
234 kCommandHelp
235 };
236
237 static int command = kCommandHelp;
238 static bool useDirect = false;
239
240 static void tests(const char *itemName)
241 {
242 dispatch_queue_t generalq = dispatch_queue_create("general", DISPATCH_QUEUE_SERIAL);
243 dispatch_group_t work_group = dispatch_group_create();
244
245 #if 0
246 if (useDirect)
247 {
248 SOSCloudKeychainServerInit();
249 }
250 #endif
251 SOSCloudKeychainSetCallbackMethodXPC(); // call this first
252
253 pass("Command: %d", command);
254 switch (command)
255 {
256 case kCommandClear:
257 ok(testClearAll(generalq, work_group), "test Clear All");
258 break;
259 case kCommandDump:
260 {
261 CFArrayRef keysToGet = NULL;
262 if (itemName)
263 {
264 CFStringRef itemStr = CFStringCreateWithCString(kCFAllocatorDefault, itemName, kCFStringEncodingUTF8);
265 pass("Retrieving : %@", itemStr);
266 keysToGet = CFArrayCreateForCFTypes(kCFAllocatorDefault, itemStr);
267 CFReleaseSafe(itemStr);
268 }
269 CFTypeRef objects = testGetObjectsFromCloud(keysToGet, generalq, work_group);
270 CFReleaseSafe(keysToGet);
271 pass(" : %@", objects);
272 displayCircles(objects);
273 }
274 break;
275 case kCommandPutCircle:
276 createAndPutInitialCircle();
277 break;
278 case kCommandNotify:
279 postCircleChangeNotification();
280 break;
281 case kCommandSynchronize:
282 requestSynchronization(generalq, work_group);
283 break;
284 case kCommandInfo:
285 dumpCircleInfo();
286 break;
287 default:
288 case kCommandHelp:
289 usage();
290 break;
291 }
292 }
293
294 int sc_kvstool(int argc, char *const *argv)
295 {
296 char *itemName = NULL;
297 // extern int optind;
298 extern char *optarg;
299 int arg, argSlot;
300
301 while (argSlot = -1, (arg = getopt_long(argc, (char * const *)argv, "ivChpdns", options, &argSlot)) != -1)
302 switch (arg)
303 {
304 case 'd':
305 itemName = (char *)(optarg);
306 command = kCommandDump;
307 break;
308 case 'C': // should set up to call testClearAll
309 command = kCommandClear;
310 break;
311 case 'p':
312 command = kCommandPutCircle;
313 break;
314 case 'n':
315 command = kCommandNotify;
316 break;
317 case 's':
318 command = kCommandSynchronize;
319 break;
320 case 'i':
321 command = kCommandInfo;
322 break;
323 case 'D':
324 useDirect = true;
325 printf("Using direct calls to KVS\n");
326 break;
327 default:
328 secerror("arg: %s", optarg);
329 break;
330 }
331
332 plan_tests(kTestCount);
333
334 secerror("Command: %d", command);
335 printf("Command: %d\n", command);
336
337 tests(itemName);
338
339 return 0;
340 }