]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/Regressions/SOSRegressionUtilities.c
Security-57337.40.85.tar.gz
[apple/security.git] / OSX / sec / SOSCircle / Regressions / SOSRegressionUtilities.c
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 // SOSRegressionUtilities.c
26 //
27
28 #include <AssertMacros.h>
29 #include <stdio.h>
30 #include <Security/SecItem.h>
31
32 #include <utilities/SecCFWrappers.h>
33 #include <utilities/debugging.h>
34
35 #include <Security/SecureObjectSync/SOSAccount.h>
36 #include <Security/SecureObjectSync/SOSAccountPriv.h>
37 #include <Security/SecureObjectSync/SOSCircle.h>
38 #include <Security/SecureObjectSync/SOSInternal.h>
39 #include <Security/SecureObjectSync/SOSPeerInfoInternal.h>
40
41 #include <SOSCloudKeychainClient.h>
42 #include "SOSRegressionUtilities.h"
43 #include "SOSInternal.h"
44
45 #if TARGET_OS_IPHONE
46 #include <MobileGestalt.h>
47 #endif
48
49 static const uint64_t maxTimeToWaitInSeconds = 30ull * NSEC_PER_SEC;
50
51 // MARK: ----- SOS General -----
52
53 const char *cloudKeychainProxyPath = "/System/Library/Frameworks/Security.framework/Resources/CloudKeychainProxy.bundle/CloudKeychainProxy";
54
55 static const char *basecfabsoluteTimeToString(CFAbsoluteTime abstime, CFTimeZoneRef tz)
56 {
57 CFGregorianDate greg = CFAbsoluteTimeGetGregorianDate(abstime, NULL);
58 char str[20];
59 if (19 != snprintf(str, 20, "%4.4d-%2.2d-%2.2d_%2.2d:%2.2d:%2.2d",
60 (int)greg.year, greg.month, greg.day, greg.hour, greg.minute, (int)greg.second))
61 str[0]=0;
62 char *data = (char *)malloc(20);
63 strncpy(data, str, 20);
64 return data;
65 }
66
67 const char *cfabsoluteTimeToString(CFAbsoluteTime abstime)
68 {
69 return basecfabsoluteTimeToString(abstime, NULL);
70 }
71
72 const char *cfabsoluteTimeToStringLocal(CFAbsoluteTime abstime)
73 {
74 // Caller must release using free
75 CFDateFormatterRef formatter = NULL;
76 CFTimeZoneRef tz = NULL;
77 CFLocaleRef locale = NULL;
78 CFDateRef date = NULL;
79 CFStringRef cftime_string = NULL;
80 char *time_string = NULL;
81 char buffer[1024] = {0,};
82 size_t sz;
83
84 require(tz = CFTimeZoneCopySystem(), xit);
85 require(locale = CFLocaleCreate(NULL, CFSTR("en_US")), xit);
86
87 require(formatter = CFDateFormatterCreate(kCFAllocatorDefault, locale, kCFDateFormatterShortStyle, kCFDateFormatterShortStyle), xit);
88 CFDateFormatterSetFormat(formatter, CFSTR("MM/dd/yy HH:mm:ss.SSS zzz"));
89 require(date = CFDateCreate(kCFAllocatorDefault, abstime), xit);
90 require(cftime_string = CFDateFormatterCreateStringWithDate(kCFAllocatorDefault, formatter, date), xit);
91
92 CFStringGetCString(cftime_string, buffer, 1024, kCFStringEncodingUTF8);
93 sz = strnlen(buffer, 1024);
94 time_string = (char *)malloc(sz);
95 strncpy(time_string, buffer, sz+1);
96 xit:
97 CFReleaseSafe(tz);
98 CFReleaseSafe(formatter);
99 CFReleaseSafe(locale);
100 CFReleaseSafe(date);
101 CFReleaseSafe(cftime_string);
102 return time_string;
103 }
104
105 #include <sys/stat.h>
106
107 static int file_exist (const char *filename)
108 {
109 struct stat buffer;
110 return (stat (filename, &buffer) == 0);
111 }
112
113 bool XPCServiceInstalled(void)
114 {
115 return file_exist(cloudKeychainProxyPath);
116 }
117
118 void registerForKVSNotifications(const void *observer, CFStringRef name, CFNotificationCallback callBack)
119 {
120 // observer is basically a context; name may not be null
121 CFNotificationCenterRef center = CFNotificationCenterGetDarwinNotifyCenter();
122 CFNotificationSuspensionBehavior suspensionBehavior = CFNotificationSuspensionBehaviorDeliverImmediately; //ignored?
123 CFNotificationCenterAddObserver(center, observer, callBack, name, NULL, suspensionBehavior);
124 }
125
126 bool testPutObjectInCloudAndSync(CFStringRef key, CFTypeRef object, CFErrorRef *error, dispatch_group_t dgroup, dispatch_queue_t processQueue)
127 {
128 bool result = testPutObjectInCloud(key, object, error, dgroup, processQueue);
129 testSynchronize(processQueue, dgroup);
130
131 return result;
132 }
133
134 bool testPutObjectInCloud(CFStringRef key, CFTypeRef object, CFErrorRef *error, dispatch_group_t dgroup, dispatch_queue_t processQueue)
135 {
136 secnotice("test", "testPutObjectInCloud: key: %@, %@", key, object);
137 CFDictionaryRef objects = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, key, object, NULL);
138 if (objects)
139 {
140 dispatch_group_enter(dgroup);
141 SOSCloudKeychainPutObjectsInCloud(objects, processQueue, ^ (CFDictionaryRef returnedValues, CFErrorRef error)
142 {
143 secnotice("test", "testPutObjectInCloud returned: %@", returnedValues);
144 if (error)
145 {
146 secnotice("test", "testPutObjectInCloud returned: %@", error);
147 CFRelease(error);
148 }
149 dispatch_group_leave(dgroup);
150 });
151 CFRelease(objects);
152 }
153
154 return true;
155 }
156
157 CFTypeRef testGetObjectFromCloud(CFStringRef key, dispatch_queue_t processQueue, dispatch_group_t dgroup)
158 {
159 // TODO: make sure we return NULL, not CFNull
160 secnotice("test", "start");
161 CFMutableArrayRef keysToGet = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
162 CFArrayAppendValue(keysToGet, key);
163
164 __block CFTypeRef object = NULL;
165
166 dispatch_semaphore_t waitSemaphore = dispatch_semaphore_create(0);
167 dispatch_time_t finishTime = dispatch_time(DISPATCH_TIME_NOW, maxTimeToWaitInSeconds);
168
169 dispatch_group_enter(dgroup);
170 SOSCloudKeychainGetObjectsFromCloud(keysToGet, processQueue, ^ (CFDictionaryRef returnedValues, CFErrorRef error)
171 {
172 secnotice("test", "SOSCloudKeychainGetObjectsFromCloud returned: %@", returnedValues);
173 if (returnedValues)
174 {
175 object = (CFTypeRef)CFDictionaryGetValue(returnedValues, key);
176 if (object)
177 CFRetain(object);
178 }
179 if (error)
180 {
181 secerror("SOSCloudKeychainGetObjectsFromCloud returned error: %@", error);
182 // CFRelease(*error);
183 }
184 dispatch_group_leave(dgroup);
185 secnotice("test", "SOSCloudKeychainGetObjectsFromCloud block exit: %@", object);
186 dispatch_semaphore_signal(waitSemaphore);
187 });
188
189 dispatch_semaphore_wait(waitSemaphore, finishTime);
190 dispatch_release(waitSemaphore);
191 if (object && (CFGetTypeID(object) == CFNullGetTypeID())) // return a NULL instead of a CFNull
192 {
193 CFRelease(object);
194 object = NULL;
195 }
196 secnotice("test", "returned: %@", object);
197 return object;
198 }
199
200 CFTypeRef testGetObjectsFromCloud(CFArrayRef keysToGet, dispatch_queue_t processQueue, dispatch_group_t dgroup)
201 {
202 __block CFTypeRef object = NULL;
203
204 dispatch_semaphore_t waitSemaphore = dispatch_semaphore_create(0);
205 dispatch_time_t finishTime = dispatch_time(DISPATCH_TIME_NOW, maxTimeToWaitInSeconds);
206
207 dispatch_group_enter(dgroup);
208
209 CloudKeychainReplyBlock replyBlock =
210 ^ (CFDictionaryRef returnedValues, CFErrorRef error)
211 {
212 secnotice("test", "SOSCloudKeychainGetObjectsFromCloud returned: %@", returnedValues);
213 object = returnedValues;
214 if (object)
215 CFRetain(object);
216 if (error)
217 {
218 secerror("SOSCloudKeychainGetObjectsFromCloud returned error: %@", error);
219 // CFRelease(*error);
220 }
221 dispatch_group_leave(dgroup);
222 secnotice("test", "SOSCloudKeychainGetObjectsFromCloud block exit: %@", object);
223 dispatch_semaphore_signal(waitSemaphore);
224 };
225
226 if (!keysToGet)
227 SOSCloudKeychainGetAllObjectsFromCloud(processQueue, replyBlock);
228 else
229 SOSCloudKeychainGetObjectsFromCloud(keysToGet, processQueue, replyBlock);
230
231 dispatch_semaphore_wait(waitSemaphore, finishTime);
232 dispatch_release(waitSemaphore);
233 if (object && (CFGetTypeID(object) == CFNullGetTypeID())) // return a NULL instead of a CFNull
234 {
235 CFRelease(object);
236 object = NULL;
237 }
238 secnotice("test", "returned: %@", object);
239 return object;
240 }
241
242 bool testSynchronize(dispatch_queue_t processQueue, dispatch_group_t dgroup)
243 {
244 __block bool result = false;
245 dispatch_semaphore_t waitSemaphore = dispatch_semaphore_create(0);
246 dispatch_time_t finishTime = dispatch_time(DISPATCH_TIME_NOW, maxTimeToWaitInSeconds);
247
248 dispatch_group_enter(dgroup);
249
250 SOSCloudKeychainSynchronize(processQueue, ^(CFDictionaryRef returnedValues, CFErrorRef error)
251 {
252 result = true;
253 dispatch_group_leave(dgroup);
254 dispatch_semaphore_signal(waitSemaphore);
255 });
256
257 dispatch_semaphore_wait(waitSemaphore, finishTime);
258 dispatch_release(waitSemaphore);
259 return result;
260 }
261
262 bool testClearAll(dispatch_queue_t processQueue, dispatch_group_t dgroup)
263 {
264 __block bool result = false;
265 dispatch_semaphore_t waitSemaphore = dispatch_semaphore_create(0);
266 dispatch_time_t finishTime = dispatch_time(DISPATCH_TIME_NOW, maxTimeToWaitInSeconds);
267
268 dispatch_group_enter(dgroup);
269
270 SOSCloudKeychainClearAll(processQueue, ^(CFDictionaryRef returnedValues, CFErrorRef error)
271 {
272 result = true;
273 secnotice("test", "SOSCloudKeychainClearAll returned: %@", error);
274 dispatch_group_leave(dgroup);
275 dispatch_semaphore_signal(waitSemaphore);
276 });
277
278 dispatch_semaphore_wait(waitSemaphore, finishTime);
279 dispatch_release(waitSemaphore);
280 secnotice("test", "SOSCloudKeychainClearAll exit");
281 return result;
282 }
283
284 void unregisterFromKVSNotifications(const void *observer)
285 {
286 CFNotificationCenterRemoveEveryObserver(CFNotificationCenterGetDarwinNotifyCenter(), observer);
287 }
288
289 //
290 // MARK: SOSPeerInfo creation helpers
291 //
292
293 CFDictionaryRef SOSCreatePeerGestaltFromName(CFStringRef name)
294 {
295 return CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
296 kPIUserDefinedDeviceNameKey, name,
297 NULL);
298 }
299
300
301 SOSPeerInfoRef SOSCreatePeerInfoFromName(CFStringRef name, SecKeyRef* outSigningKey, CFErrorRef *error)
302 {
303 SOSPeerInfoRef result = NULL;
304 SecKeyRef publicKey = NULL;
305 CFDictionaryRef gestalt = NULL;
306
307 require(outSigningKey, exit);
308
309 GeneratePermanentECPair(256, &publicKey, outSigningKey);
310
311 gestalt = SOSCreatePeerGestaltFromName(name);
312 require(gestalt, exit);
313
314 result = SOSPeerInfoCreate(NULL, gestalt, NULL, *outSigningKey, error);
315
316 exit:
317 CFReleaseNull(gestalt);
318 CFReleaseNull(publicKey);
319
320 return result;
321 }
322
323 SOSFullPeerInfoRef SOSCreateFullPeerInfoFromName(CFStringRef name, SecKeyRef* outSigningKey, CFErrorRef *error)
324 {
325 SOSFullPeerInfoRef result = NULL;
326 SecKeyRef publicKey = NULL;
327 CFDictionaryRef gestalt = NULL;
328
329 require(outSigningKey, exit);
330
331 //GeneratePermanentECPair(256, &publicKey, outSigningKey);
332 *outSigningKey = GeneratePermanentFullECKey(256, name, error);
333 require(*outSigningKey, exit);
334
335 gestalt = SOSCreatePeerGestaltFromName(name);
336 require(gestalt, exit);
337
338 result = SOSFullPeerInfoCreate(NULL, gestalt, NULL, *outSigningKey, error);
339
340 exit:
341 CFReleaseNull(gestalt);
342 CFReleaseNull(publicKey);
343
344 return result;
345 }
346
347 // MARK: ----- MAC Address -----
348
349 /*
350 * Name: GetHardwareAdress
351 *
352 * Parameters: None.
353 *
354 * Returns: Nothing
355 *
356 * Description: Retrieve the hardare address for a specified network interface
357 *
358 */
359
360 #include <stdlib.h>
361 #include <string.h>
362
363 #include <sys/socket.h>
364 #include <netinet/in.h>
365 #include <sys/sysctl.h>
366 #include <net/if.h>
367 #include <net/if_dl.h>
368 #include <net/route.h>
369
370 #include <unistd.h>
371 #include <netdb.h>
372 #include <sys/stat.h>
373
374 static int getHardwareAddress(const char *interfaceName, size_t maxLenAllowed, size_t *outActualLength, char *outHardwareAddress)
375 {
376 char *end;
377 struct if_msghdr *ifm;
378 struct sockaddr_dl *sdl;
379 char *buf;
380 int result = -1;
381 size_t buffSize;
382 int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET, NET_RT_IFLIST, 0 };
383
384 buf = 0;
385 *outActualLength = 0;
386 // see how much space is needed
387 require_noerr(result = sysctl(mib, 6, NULL, &buffSize, NULL, 0), xit);
388
389 // allocate the buffer
390 require(buf = malloc(buffSize), xit);
391
392 // get the interface info
393 require_noerr(result = sysctl(mib, 6, buf, &buffSize, NULL, 0), xit);
394
395 ifm = (struct if_msghdr *) buf;
396 end = buf + buffSize;
397 do
398 {
399 if (ifm->ifm_type == RTM_IFINFO) // should always be true
400 {
401 sdl = (struct sockaddr_dl *) (ifm + 1);
402 if ( sdl->sdl_nlen == strlen( interfaceName ) && ( bcmp( sdl->sdl_data, interfaceName, sdl->sdl_nlen ) == 0 ) )
403 {
404 if ( sdl->sdl_alen > 0 )
405 {
406 size_t hardwareLen;
407
408 result = 0; // indicate found the interface
409 hardwareLen = sdl->sdl_alen;
410 if ( hardwareLen > maxLenAllowed )
411 {
412 hardwareLen = maxLenAllowed;
413 result = -2; // indicate truncation of the address
414 }
415 memcpy( outHardwareAddress, sdl->sdl_data + sdl->sdl_nlen, hardwareLen );
416 *outActualLength = hardwareLen;
417 break;
418
419 }
420 }
421 }
422 ifm = (struct if_msghdr *) ((char*)ifm + ifm->ifm_msglen);
423 } while ( (char*)ifm < end );
424
425 xit:
426 if (buf)
427 free(buf);
428
429 return result;
430 }
431
432 // MARK: ----- cloudTransportTests -----
433
434 CFStringRef myMacAddress(void)
435 {
436 // 6 bytes, no ":"s
437 CFStringRef result = NULL;
438 const char *interfaceName = "en0";
439 size_t maxLenAllowed = 1024;
440 size_t outActualLength = 0;
441 char outHardwareAddress[1024];
442
443 require_noerr(getHardwareAddress(interfaceName, maxLenAllowed, &outActualLength, outHardwareAddress), xit);
444 require(outActualLength==6, xit);
445 unsigned char buf[32]={0,};
446
447 unsigned char *ps = (unsigned char *)buf;
448 unsigned char *pa = (unsigned char *)outHardwareAddress;
449 for (int ix = 0; ix < 6; ix++, pa++)
450 ps += sprintf((char *)ps, "%02x", *pa);
451
452 result = CFStringCreateWithCString(kCFAllocatorDefault, (const char *)buf, kCFStringEncodingUTF8);
453
454 xit:
455 return result;
456 }