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@
25 // SOSRegressionUtilities.c
28 #include <AssertMacros.h>
30 #include <Security/SecItem.h>
32 #include <utilities/SecCFWrappers.h>
33 #include <utilities/debugging.h>
35 #include <SecureObjectSync/SOSAccount.h>
36 #include <SecureObjectSync/SOSCircle.h>
37 #include <SecureObjectSync/SOSInternal.h>
38 #include <SecureObjectSync/SOSPeerInfoInternal.h>
40 #include <SOSCloudKeychainClient.h>
41 #include "SOSRegressionUtilities.h"
42 #include "SOSInternal.h"
45 #include <MobileGestalt.h>
48 static const uint64_t maxTimeToWaitInSeconds
= 30ull * NSEC_PER_SEC
;
50 // MARK: ----- SOS General -----
52 const char *cloudKeychainProxyPath
= "/System/Library/Frameworks/Security.framework/Resources/CloudKeychainProxy.bundle/CloudKeychainProxy";
54 static const char *basecfabsoluteTimeToString(CFAbsoluteTime abstime
, CFTimeZoneRef tz
)
56 CFGregorianDate greg
= CFAbsoluteTimeGetGregorianDate(abstime
, NULL
);
58 if (19 != snprintf(str
, 20, "%4.4d-%2.2d-%2.2d_%2.2d:%2.2d:%2.2d",
59 (int)greg
.year
, greg
.month
, greg
.day
, greg
.hour
, greg
.minute
, (int)greg
.second
))
61 char *data
= (char *)malloc(20);
62 strncpy(data
, str
, 20);
66 const char *cfabsoluteTimeToString(CFAbsoluteTime abstime
)
68 return basecfabsoluteTimeToString(abstime
, NULL
);
71 const char *cfabsoluteTimeToStringLocal(CFAbsoluteTime abstime
)
73 // Caller must release using free
74 CFDateFormatterRef formatter
= NULL
;
75 CFTimeZoneRef tz
= NULL
;
76 CFLocaleRef locale
= NULL
;
77 CFDateRef date
= NULL
;
78 CFStringRef cftime_string
= NULL
;
79 char *time_string
= NULL
;
80 char buffer
[1024] = {0,};
83 require(tz
= CFTimeZoneCopySystem(), xit
);
84 require(locale
= CFLocaleCreate(NULL
, CFSTR("en_US")), xit
);
86 require(formatter
= CFDateFormatterCreate(kCFAllocatorDefault
, locale
, kCFDateFormatterShortStyle
, kCFDateFormatterShortStyle
), xit
);
87 CFDateFormatterSetFormat(formatter
, CFSTR("MM/dd/yy HH:mm:ss.SSS zzz"));
88 require(date
= CFDateCreate(kCFAllocatorDefault
, abstime
), xit
);
89 require(cftime_string
= CFDateFormatterCreateStringWithDate(kCFAllocatorDefault
, formatter
, date
), xit
);
91 CFStringGetCString(cftime_string
, buffer
, 1024, kCFStringEncodingUTF8
);
92 sz
= strnlen(buffer
, 1024);
93 time_string
= (char *)malloc(sz
);
94 strncpy(time_string
, buffer
, sz
+1);
97 CFReleaseSafe(formatter
);
98 CFReleaseSafe(locale
);
100 CFReleaseSafe(cftime_string
);
104 #include <sys/stat.h>
106 static int file_exist (const char *filename
)
109 return (stat (filename
, &buffer
) == 0);
112 bool XPCServiceInstalled(void)
114 return file_exist(cloudKeychainProxyPath
);
117 void registerForKVSNotifications(const void *observer
, CFStringRef name
, CFNotificationCallback callBack
)
119 // observer is basically a context; name may not be null
120 CFNotificationCenterRef center
= CFNotificationCenterGetDarwinNotifyCenter();
121 CFNotificationSuspensionBehavior suspensionBehavior
= CFNotificationSuspensionBehaviorDeliverImmediately
; //ignored?
122 CFNotificationCenterAddObserver(center
, observer
, callBack
, name
, NULL
, suspensionBehavior
);
125 bool testPutObjectInCloudAndSync(CFStringRef key
, CFTypeRef object
, CFErrorRef
*error
, dispatch_group_t dgroup
, dispatch_queue_t processQueue
)
127 bool result
= testPutObjectInCloud(key
, object
, error
, dgroup
, processQueue
);
128 testSynchronize(processQueue
, dgroup
);
133 bool testPutObjectInCloud(CFStringRef key
, CFTypeRef object
, CFErrorRef
*error
, dispatch_group_t dgroup
, dispatch_queue_t processQueue
)
135 secerror("testPutObjectInCloud: key: %@, %@", key
, object
);
136 CFDictionaryRef objects
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
, key
, object
, NULL
);
139 dispatch_group_enter(dgroup
);
140 SOSCloudKeychainPutObjectsInCloud(objects
, processQueue
, ^ (CFDictionaryRef returnedValues
, CFErrorRef error
)
142 secerror("testPutObjectInCloud returned: %@", returnedValues
);
145 secerror("testPutObjectInCloud returned: %@", error
);
148 dispatch_group_leave(dgroup
);
156 CFTypeRef
testGetObjectFromCloud(CFStringRef key
, dispatch_queue_t processQueue
, dispatch_group_t dgroup
)
158 // TODO: make sure we return NULL, not CFNull
160 CFMutableArrayRef keysToGet
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
161 CFArrayAppendValue(keysToGet
, key
);
163 __block CFTypeRef object
= NULL
;
165 dispatch_semaphore_t waitSemaphore
= dispatch_semaphore_create(0);
166 dispatch_time_t finishTime
= dispatch_time(DISPATCH_TIME_NOW
, maxTimeToWaitInSeconds
);
168 dispatch_group_enter(dgroup
);
169 SOSCloudKeychainGetObjectsFromCloud(keysToGet
, processQueue
, ^ (CFDictionaryRef returnedValues
, CFErrorRef error
)
171 secerror("SOSCloudKeychainGetObjectsFromCloud returned: %@", returnedValues
);
174 object
= (CFTypeRef
)CFDictionaryGetValue(returnedValues
, key
);
180 secerror("SOSCloudKeychainGetObjectsFromCloud returned error: %@", error
);
181 // CFRelease(*error);
183 dispatch_group_leave(dgroup
);
184 secerror("SOSCloudKeychainGetObjectsFromCloud block exit: %@", object
);
185 dispatch_semaphore_signal(waitSemaphore
);
188 dispatch_semaphore_wait(waitSemaphore
, finishTime
);
189 dispatch_release(waitSemaphore
);
190 if (object
&& (CFGetTypeID(object
) == CFNullGetTypeID())) // return a NULL instead of a CFNull
195 secerror("returned: %@", object
);
199 CFTypeRef
testGetObjectsFromCloud(CFArrayRef keysToGet
, dispatch_queue_t processQueue
, dispatch_group_t dgroup
)
201 __block CFTypeRef object
= NULL
;
203 dispatch_semaphore_t waitSemaphore
= dispatch_semaphore_create(0);
204 dispatch_time_t finishTime
= dispatch_time(DISPATCH_TIME_NOW
, maxTimeToWaitInSeconds
);
206 dispatch_group_enter(dgroup
);
208 CloudKeychainReplyBlock replyBlock
=
209 ^ (CFDictionaryRef returnedValues
, CFErrorRef error
)
211 secerror("SOSCloudKeychainGetObjectsFromCloud returned: %@", returnedValues
);
212 object
= returnedValues
;
217 secerror("SOSCloudKeychainGetObjectsFromCloud returned error: %@", error
);
218 // CFRelease(*error);
220 dispatch_group_leave(dgroup
);
221 secerror("SOSCloudKeychainGetObjectsFromCloud block exit: %@", object
);
222 dispatch_semaphore_signal(waitSemaphore
);
226 SOSCloudKeychainGetAllObjectsFromCloud(processQueue
, replyBlock
);
228 SOSCloudKeychainGetObjectsFromCloud(keysToGet
, processQueue
, replyBlock
);
230 dispatch_semaphore_wait(waitSemaphore
, finishTime
);
231 dispatch_release(waitSemaphore
);
232 if (object
&& (CFGetTypeID(object
) == CFNullGetTypeID())) // return a NULL instead of a CFNull
237 secerror("returned: %@", object
);
241 bool testSynchronize(dispatch_queue_t processQueue
, dispatch_group_t dgroup
)
243 __block
bool result
= false;
244 dispatch_semaphore_t waitSemaphore
= dispatch_semaphore_create(0);
245 dispatch_time_t finishTime
= dispatch_time(DISPATCH_TIME_NOW
, maxTimeToWaitInSeconds
);
247 dispatch_group_enter(dgroup
);
249 SOSCloudKeychainSynchronize(processQueue
, ^(CFDictionaryRef returnedValues
, CFErrorRef error
)
252 dispatch_group_leave(dgroup
);
253 dispatch_semaphore_signal(waitSemaphore
);
256 dispatch_semaphore_wait(waitSemaphore
, finishTime
);
257 dispatch_release(waitSemaphore
);
261 bool testClearAll(dispatch_queue_t processQueue
, dispatch_group_t dgroup
)
263 __block
bool result
= false;
264 dispatch_semaphore_t waitSemaphore
= dispatch_semaphore_create(0);
265 dispatch_time_t finishTime
= dispatch_time(DISPATCH_TIME_NOW
, maxTimeToWaitInSeconds
);
267 dispatch_group_enter(dgroup
);
269 SOSCloudKeychainClearAll(processQueue
, ^(CFDictionaryRef returnedValues
, CFErrorRef error
)
272 secerror("SOSCloudKeychainClearAll returned: %@", error
);
273 dispatch_group_leave(dgroup
);
274 dispatch_semaphore_signal(waitSemaphore
);
277 dispatch_semaphore_wait(waitSemaphore
, finishTime
);
278 dispatch_release(waitSemaphore
);
279 secerror("SOSCloudKeychainClearAll exit");
283 void unregisterFromKVSNotifications(const void *observer
)
285 CFNotificationCenterRemoveEveryObserver(CFNotificationCenterGetDarwinNotifyCenter(), observer
);
289 // MARK: SOSPeerInfo creation helpers
292 CFDictionaryRef
SOSCreatePeerGestaltFromName(CFStringRef name
)
294 return CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
295 kPIUserDefinedDeviceName
, name
,
300 SOSPeerInfoRef
SOSCreatePeerInfoFromName(CFStringRef name
, SecKeyRef
* outSigningKey
, CFErrorRef
*error
)
302 SOSPeerInfoRef result
= NULL
;
303 SecKeyRef publicKey
= NULL
;
304 CFDictionaryRef gestalt
= NULL
;
306 require(outSigningKey
, exit
);
308 GeneratePermanentECPair(256, &publicKey
, outSigningKey
);
310 gestalt
= SOSCreatePeerGestaltFromName(name
);
311 require(gestalt
, exit
);
313 result
= SOSPeerInfoCreate(NULL
, gestalt
, *outSigningKey
, error
);
316 CFReleaseNull(gestalt
);
317 CFReleaseNull(publicKey
);
322 SOSFullPeerInfoRef
SOSCreateFullPeerInfoFromName(CFStringRef name
, SecKeyRef
* outSigningKey
, CFErrorRef
*error
)
324 SOSFullPeerInfoRef result
= NULL
;
325 SecKeyRef publicKey
= NULL
;
326 CFDictionaryRef gestalt
= NULL
;
328 require(outSigningKey
, exit
);
330 GeneratePermanentECPair(256, &publicKey
, outSigningKey
);
332 gestalt
= SOSCreatePeerGestaltFromName(name
);
333 require(gestalt
, exit
);
335 result
= SOSFullPeerInfoCreate(NULL
, gestalt
, *outSigningKey
, error
);
338 CFReleaseNull(gestalt
);
339 CFReleaseNull(publicKey
);
344 // MARK: ----- MAC Address -----
347 * Name: GetHardwareAdress
353 * Description: Retrieve the hardare address for a specified network interface
360 #include <sys/socket.h>
361 #include <netinet/in.h>
362 #include <sys/sysctl.h>
364 #include <net/if_dl.h>
365 #include <net/route.h>
369 #include <sys/stat.h>
371 static int getHardwareAddress(const char *interfaceName
, size_t maxLenAllowed
, size_t *outActualLength
, char *outHardwareAddress
)
374 struct if_msghdr
*ifm
;
375 struct sockaddr_dl
*sdl
;
379 int mib
[6] = {CTL_NET
, AF_ROUTE
, 0, AF_INET
, NET_RT_IFLIST
, 0 };
382 *outActualLength
= 0;
383 // see how much space is needed
384 require_noerr(result
= sysctl(mib
, 6, NULL
, &buffSize
, NULL
, 0), xit
);
386 // allocate the buffer
387 require(buf
= malloc(buffSize
), xit
);
389 // get the interface info
390 require_noerr(result
= sysctl(mib
, 6, buf
, &buffSize
, NULL
, 0), xit
);
392 ifm
= (struct if_msghdr
*) buf
;
393 end
= buf
+ buffSize
;
396 if (ifm
->ifm_type
== RTM_IFINFO
) // should always be true
398 sdl
= (struct sockaddr_dl
*) (ifm
+ 1);
399 if ( sdl
->sdl_nlen
== strlen( interfaceName
) && ( bcmp( sdl
->sdl_data
, interfaceName
, sdl
->sdl_nlen
) == 0 ) )
401 if ( sdl
->sdl_alen
> 0 )
405 result
= 0; // indicate found the interface
406 hardwareLen
= sdl
->sdl_alen
;
407 if ( hardwareLen
> maxLenAllowed
)
409 hardwareLen
= maxLenAllowed
;
410 result
= -2; // indicate truncation of the address
412 memcpy( outHardwareAddress
, sdl
->sdl_data
+ sdl
->sdl_nlen
, hardwareLen
);
413 *outActualLength
= hardwareLen
;
419 ifm
= (struct if_msghdr
*) ((char*)ifm
+ ifm
->ifm_msglen
);
420 } while ( (char*)ifm
< end
);
429 // MARK: ----- cloudTransportTests -----
431 CFStringRef
myMacAddress(void)
434 CFStringRef result
= NULL
;
435 const char *interfaceName
= "en0";
436 size_t maxLenAllowed
= 1024;
437 size_t outActualLength
= 0;
438 char outHardwareAddress
[1024];
440 require_noerr(getHardwareAddress(interfaceName
, maxLenAllowed
, &outActualLength
, outHardwareAddress
), xit
);
441 require(outActualLength
==6, xit
);
442 unsigned char buf
[32]={0,};
444 unsigned char *ps
= (unsigned char *)buf
;
445 unsigned char *pa
= (unsigned char *)outHardwareAddress
;
446 for (int ix
= 0; ix
< 6; ix
++, pa
++)
447 ps
+= sprintf((char *)ps
, "%02x", *pa
);
449 result
= CFStringCreateWithCString(kCFAllocatorDefault
, (const char *)buf
, kCFStringEncodingUTF8
);