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