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 <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>
41 #include <SOSCloudKeychainClient.h>
42 #include "SOSRegressionUtilities.h"
43 #include "SOSInternal.h"
46 #include <MobileGestalt.h>
49 static const uint64_t maxTimeToWaitInSeconds
= 30ull * NSEC_PER_SEC
;
51 // MARK: ----- SOS General -----
53 const char *cloudKeychainProxyPath
= "/System/Library/Frameworks/Security.framework/Resources/CloudKeychainProxy.bundle/CloudKeychainProxy";
55 static const char *basecfabsoluteTimeToString(CFAbsoluteTime abstime
, CFTimeZoneRef tz
)
57 CFGregorianDate greg
= CFAbsoluteTimeGetGregorianDate(abstime
, NULL
);
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
))
62 char *data
= (char *)malloc(20);
63 strncpy(data
, str
, 20);
67 const char *cfabsoluteTimeToString(CFAbsoluteTime abstime
)
69 return basecfabsoluteTimeToString(abstime
, NULL
);
72 const char *cfabsoluteTimeToStringLocal(CFAbsoluteTime abstime
)
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,};
84 require(tz
= CFTimeZoneCopySystem(), xit
);
85 require(locale
= CFLocaleCreate(NULL
, CFSTR("en_US")), xit
);
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
);
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);
98 CFReleaseSafe(formatter
);
99 CFReleaseSafe(locale
);
101 CFReleaseSafe(cftime_string
);
105 #include <sys/stat.h>
107 static int file_exist (const char *filename
)
110 return (stat (filename
, &buffer
) == 0);
113 bool XPCServiceInstalled(void)
115 return file_exist(cloudKeychainProxyPath
);
118 void registerForKVSNotifications(const void *observer
, CFStringRef name
, CFNotificationCallback callBack
)
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
);
126 bool testPutObjectInCloudAndSync(CFStringRef key
, CFTypeRef object
, CFErrorRef
*error
, dispatch_group_t dgroup
, dispatch_queue_t processQueue
)
128 bool result
= testPutObjectInCloud(key
, object
, error
, dgroup
, processQueue
);
129 testSynchronize(processQueue
, dgroup
);
134 bool testPutObjectInCloud(CFStringRef key
, CFTypeRef object
, CFErrorRef
*error
, dispatch_group_t dgroup
, dispatch_queue_t processQueue
)
136 secnotice("test", "testPutObjectInCloud: key: %@, %@", key
, object
);
137 CFDictionaryRef objects
= CFDictionaryCreateForCFTypes(kCFAllocatorDefault
, key
, object
, NULL
);
140 dispatch_group_enter(dgroup
);
141 SOSCloudKeychainPutObjectsInCloud(objects
, processQueue
, ^ (CFDictionaryRef returnedValues
, CFErrorRef error
)
143 secnotice("test", "testPutObjectInCloud returned: %@", returnedValues
);
146 secnotice("test", "testPutObjectInCloud returned: %@", error
);
149 dispatch_group_leave(dgroup
);
157 CFTypeRef
testGetObjectFromCloud(CFStringRef key
, dispatch_queue_t processQueue
, dispatch_group_t dgroup
)
159 // TODO: make sure we return NULL, not CFNull
160 secnotice("test", "start");
161 CFMutableArrayRef keysToGet
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
);
162 CFArrayAppendValue(keysToGet
, key
);
164 __block CFTypeRef object
= NULL
;
166 dispatch_semaphore_t waitSemaphore
= dispatch_semaphore_create(0);
167 dispatch_time_t finishTime
= dispatch_time(DISPATCH_TIME_NOW
, maxTimeToWaitInSeconds
);
169 dispatch_group_enter(dgroup
);
170 SOSCloudKeychainGetObjectsFromCloud(keysToGet
, processQueue
, ^ (CFDictionaryRef returnedValues
, CFErrorRef error
)
172 secnotice("test", "SOSCloudKeychainGetObjectsFromCloud returned: %@", returnedValues
);
175 object
= (CFTypeRef
)CFDictionaryGetValue(returnedValues
, key
);
181 secerror("SOSCloudKeychainGetObjectsFromCloud returned error: %@", error
);
182 // CFRelease(*error);
184 dispatch_group_leave(dgroup
);
185 secnotice("test", "SOSCloudKeychainGetObjectsFromCloud block exit: %@", object
);
186 dispatch_semaphore_signal(waitSemaphore
);
189 dispatch_semaphore_wait(waitSemaphore
, finishTime
);
190 dispatch_release(waitSemaphore
);
191 if (object
&& (CFGetTypeID(object
) == CFNullGetTypeID())) // return a NULL instead of a CFNull
196 secnotice("test", "returned: %@", object
);
200 CFTypeRef
testGetObjectsFromCloud(CFArrayRef keysToGet
, dispatch_queue_t processQueue
, dispatch_group_t dgroup
)
202 __block CFTypeRef object
= NULL
;
204 dispatch_semaphore_t waitSemaphore
= dispatch_semaphore_create(0);
205 dispatch_time_t finishTime
= dispatch_time(DISPATCH_TIME_NOW
, maxTimeToWaitInSeconds
);
207 dispatch_group_enter(dgroup
);
209 CloudKeychainReplyBlock replyBlock
=
210 ^ (CFDictionaryRef returnedValues
, CFErrorRef error
)
212 secnotice("test", "SOSCloudKeychainGetObjectsFromCloud returned: %@", returnedValues
);
213 object
= returnedValues
;
218 secerror("SOSCloudKeychainGetObjectsFromCloud returned error: %@", error
);
219 // CFRelease(*error);
221 dispatch_group_leave(dgroup
);
222 secnotice("test", "SOSCloudKeychainGetObjectsFromCloud block exit: %@", object
);
223 dispatch_semaphore_signal(waitSemaphore
);
227 SOSCloudKeychainGetAllObjectsFromCloud(processQueue
, replyBlock
);
229 SOSCloudKeychainGetObjectsFromCloud(keysToGet
, processQueue
, replyBlock
);
231 dispatch_semaphore_wait(waitSemaphore
, finishTime
);
232 dispatch_release(waitSemaphore
);
233 if (object
&& (CFGetTypeID(object
) == CFNullGetTypeID())) // return a NULL instead of a CFNull
238 secnotice("test", "returned: %@", object
);
242 bool testSynchronize(dispatch_queue_t processQueue
, dispatch_group_t dgroup
)
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
);
248 dispatch_group_enter(dgroup
);
250 SOSCloudKeychainSynchronize(processQueue
, ^(CFDictionaryRef returnedValues
, CFErrorRef error
)
253 dispatch_group_leave(dgroup
);
254 dispatch_semaphore_signal(waitSemaphore
);
257 dispatch_semaphore_wait(waitSemaphore
, finishTime
);
258 dispatch_release(waitSemaphore
);
262 bool testClearAll(dispatch_queue_t processQueue
, dispatch_group_t dgroup
)
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
);
268 dispatch_group_enter(dgroup
);
270 SOSCloudKeychainClearAll(processQueue
, ^(CFDictionaryRef returnedValues
, CFErrorRef error
)
273 secnotice("test", "SOSCloudKeychainClearAll returned: %@", error
);
274 dispatch_group_leave(dgroup
);
275 dispatch_semaphore_signal(waitSemaphore
);
278 dispatch_semaphore_wait(waitSemaphore
, finishTime
);
279 dispatch_release(waitSemaphore
);
280 secnotice("test", "SOSCloudKeychainClearAll exit");
284 void unregisterFromKVSNotifications(const void *observer
)
286 CFNotificationCenterRemoveEveryObserver(CFNotificationCenterGetDarwinNotifyCenter(), observer
);
290 // MARK: SOSPeerInfo creation helpers
293 CFDictionaryRef
SOSCreatePeerGestaltFromName(CFStringRef name
)
295 return CFDictionaryCreateForCFTypes(kCFAllocatorDefault
,
296 kPIUserDefinedDeviceNameKey
, name
,
301 SOSPeerInfoRef
SOSCreatePeerInfoFromName(CFStringRef name
, SecKeyRef
* outSigningKey
, CFErrorRef
*error
)
303 SOSPeerInfoRef result
= NULL
;
304 SecKeyRef publicKey
= NULL
;
305 CFDictionaryRef gestalt
= NULL
;
307 require(outSigningKey
, exit
);
309 GeneratePermanentECPair(256, &publicKey
, outSigningKey
);
311 gestalt
= SOSCreatePeerGestaltFromName(name
);
312 require(gestalt
, exit
);
314 result
= SOSPeerInfoCreate(NULL
, gestalt
, NULL
, *outSigningKey
, error
);
317 CFReleaseNull(gestalt
);
318 CFReleaseNull(publicKey
);
323 SOSFullPeerInfoRef
SOSCreateFullPeerInfoFromName(CFStringRef name
, SecKeyRef
* outSigningKey
, CFErrorRef
*error
)
325 SOSFullPeerInfoRef result
= NULL
;
326 SecKeyRef publicKey
= NULL
;
327 CFDictionaryRef gestalt
= NULL
;
329 require(outSigningKey
, exit
);
331 //GeneratePermanentECPair(256, &publicKey, outSigningKey);
332 *outSigningKey
= GeneratePermanentFullECKey(256, name
, error
);
333 require(*outSigningKey
, exit
);
335 gestalt
= SOSCreatePeerGestaltFromName(name
);
336 require(gestalt
, exit
);
338 result
= SOSFullPeerInfoCreate(NULL
, gestalt
, NULL
, *outSigningKey
, error
);
341 CFReleaseNull(gestalt
);
342 CFReleaseNull(publicKey
);
347 // MARK: ----- MAC Address -----
350 * Name: GetHardwareAdress
356 * Description: Retrieve the hardare address for a specified network interface
363 #include <sys/socket.h>
364 #include <netinet/in.h>
365 #include <sys/sysctl.h>
367 #include <net/if_dl.h>
368 #include <net/route.h>
372 #include <sys/stat.h>
374 static int getHardwareAddress(const char *interfaceName
, size_t maxLenAllowed
, size_t *outActualLength
, char *outHardwareAddress
)
377 struct if_msghdr
*ifm
;
378 struct sockaddr_dl
*sdl
;
382 int mib
[6] = {CTL_NET
, AF_ROUTE
, 0, AF_INET
, NET_RT_IFLIST
, 0 };
385 *outActualLength
= 0;
386 // see how much space is needed
387 require_noerr(result
= sysctl(mib
, 6, NULL
, &buffSize
, NULL
, 0), xit
);
389 // allocate the buffer
390 require(buf
= malloc(buffSize
), xit
);
392 // get the interface info
393 require_noerr(result
= sysctl(mib
, 6, buf
, &buffSize
, NULL
, 0), xit
);
395 ifm
= (struct if_msghdr
*) buf
;
396 end
= buf
+ buffSize
;
399 if (ifm
->ifm_type
== RTM_IFINFO
) // should always be true
401 sdl
= (struct sockaddr_dl
*) (ifm
+ 1);
402 if ( sdl
->sdl_nlen
== strlen( interfaceName
) && ( bcmp( sdl
->sdl_data
, interfaceName
, sdl
->sdl_nlen
) == 0 ) )
404 if ( sdl
->sdl_alen
> 0 )
408 result
= 0; // indicate found the interface
409 hardwareLen
= sdl
->sdl_alen
;
410 if ( hardwareLen
> maxLenAllowed
)
412 hardwareLen
= maxLenAllowed
;
413 result
= -2; // indicate truncation of the address
415 memcpy( outHardwareAddress
, sdl
->sdl_data
+ sdl
->sdl_nlen
, hardwareLen
);
416 *outActualLength
= hardwareLen
;
422 ifm
= (struct if_msghdr
*) ((char*)ifm
+ ifm
->ifm_msglen
);
423 } while ( (char*)ifm
< end
);
432 // MARK: ----- cloudTransportTests -----
434 CFStringRef
myMacAddress(void)
437 CFStringRef result
= NULL
;
438 const char *interfaceName
= "en0";
439 size_t maxLenAllowed
= 1024;
440 size_t outActualLength
= 0;
441 char outHardwareAddress
[1024];
443 require_noerr(getHardwareAddress(interfaceName
, maxLenAllowed
, &outActualLength
, outHardwareAddress
), xit
);
444 require(outActualLength
==6, xit
);
445 unsigned char buf
[32]={0,};
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
);
452 result
= CFStringCreateWithCString(kCFAllocatorDefault
, (const char *)buf
, kCFStringEncodingUTF8
);