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 "keychain/SecureObjectSync/SOSAccount.h"
36 #include "keychain/SecureObjectSync/SOSAccountPriv.h"
37 #include "keychain/SecureObjectSync/SOSCircle.h"
38 #include "keychain/SecureObjectSync/SOSInternal.h"
39 #include "keychain/SecureObjectSync/SOSPeerInfoInternal.h"
41 #include "keychain/SecureObjectSync/CKBridge/SOSCloudKeychainClient.h"
42 #include "SOSRegressionUtilities.h"
43 #include "keychain/SecureObjectSync/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 if (object && (CFGetTypeID(object) == CFNullGetTypeID())) // return a NULL instead of a CFNull
195 secnotice("test", "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);
205 dispatch_group_enter(dgroup);
207 CloudKeychainReplyBlock replyBlock =
208 ^ (CFDictionaryRef returnedValues, CFErrorRef error)
210 secnotice("test", "SOSCloudKeychainGetObjectsFromCloud returned: %@", returnedValues);
211 object = returnedValues;
216 secerror("SOSCloudKeychainGetObjectsFromCloud returned error: %@", error);
218 dispatch_group_leave(dgroup);
219 secnotice("test", "SOSCloudKeychainGetObjectsFromCloud block exit: %@", object);
220 dispatch_semaphore_signal(waitSemaphore);
224 SOSCloudKeychainGetAllObjectsFromCloud(processQueue, replyBlock);
226 SOSCloudKeychainGetObjectsFromCloud(keysToGet, processQueue, replyBlock);
229 dispatch_semaphore_wait(waitSemaphore, finishTime);
230 if (object && (CFGetTypeID(object) == CFNullGetTypeID())) // return a NULL instead of a CFNull
235 secnotice("test", "returned: %@", object);
239 bool testSynchronize(dispatch_queue_t processQueue, dispatch_group_t dgroup)
241 __block bool result = false;
242 dispatch_semaphore_t waitSemaphore = dispatch_semaphore_create(0);
243 dispatch_time_t finishTime = dispatch_time(DISPATCH_TIME_NOW, maxTimeToWaitInSeconds);
245 dispatch_group_enter(dgroup);
247 SOSCloudKeychainSynchronize(processQueue, ^(CFDictionaryRef returnedValues, CFErrorRef error)
250 dispatch_group_leave(dgroup);
251 dispatch_semaphore_signal(waitSemaphore);
254 dispatch_semaphore_wait(waitSemaphore, finishTime);
258 bool testClearAll(dispatch_queue_t processQueue, dispatch_group_t dgroup)
260 __block bool result = false;
261 dispatch_semaphore_t waitSemaphore = dispatch_semaphore_create(0);
262 dispatch_time_t finishTime = dispatch_time(DISPATCH_TIME_NOW, maxTimeToWaitInSeconds);
264 dispatch_group_enter(dgroup);
266 secnotice("circleOps", "SOSCloudKeychainClearAll called by testClearAll");
267 SOSCloudKeychainClearAll(processQueue, ^(CFDictionaryRef returnedValues, CFErrorRef error)
270 secnotice("test", "SOSCloudKeychainClearAll returned: %@", error);
271 dispatch_group_leave(dgroup);
272 dispatch_semaphore_signal(waitSemaphore);
275 dispatch_semaphore_wait(waitSemaphore, finishTime);
276 secnotice("test", "SOSCloudKeychainClearAll exit");
280 void unregisterFromKVSNotifications(const void *observer)
282 CFNotificationCenterRemoveEveryObserver(CFNotificationCenterGetDarwinNotifyCenter(), observer);
286 // MARK: SOSPeerInfo creation helpers
289 CFDictionaryRef SOSCreatePeerGestaltFromName(CFStringRef name)
291 return CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
292 kPIUserDefinedDeviceNameKey, name,
297 SOSPeerInfoRef SOSCreatePeerInfoFromName(CFStringRef name,
298 SecKeyRef* outSigningKey,
299 SecKeyRef* outOctagonSigningKey,
300 SecKeyRef* outOctagonEncryptionKey,
303 SOSPeerInfoRef result = NULL;
304 SecKeyRef publicKey = NULL;
305 SecKeyRef octagonSigningPublicKey = NULL;
306 SecKeyRef octagonEncryptionPublicKey = NULL;
307 CFDictionaryRef gestalt = NULL;
309 require(outSigningKey, exit);
311 require_quiet(SecError(GeneratePermanentECPair(256, &publicKey, outSigningKey), error, CFSTR("Failed To Create Key")), exit);
312 require_quiet(SecError(GeneratePermanentECPair(384, &octagonSigningPublicKey, outOctagonSigningKey), error, CFSTR("Failed to Create Octagon Signing Key")), exit);
313 require_quiet(SecError(GeneratePermanentECPair(384, &octagonEncryptionPublicKey, outOctagonEncryptionKey), error, CFSTR("Failed to Create Octagon Encryption Key")), exit);
315 gestalt = SOSCreatePeerGestaltFromName(name);
316 require(gestalt, exit);
318 result = SOSPeerInfoCreate(NULL, gestalt, NULL, *outSigningKey,
319 *outOctagonSigningKey, *outOctagonEncryptionKey,
320 // Always support CKKS4All for now
325 CFReleaseNull(gestalt);
326 CFReleaseNull(publicKey);
327 CFReleaseNull(octagonSigningPublicKey);
328 CFReleaseNull(octagonEncryptionPublicKey);
333 SOSFullPeerInfoRef SOSCreateFullPeerInfoFromName(CFStringRef name,
334 SecKeyRef* outSigningKey,
335 SecKeyRef* outOctagonSigningKey,
336 SecKeyRef* outOctagonEncryptionKey,
339 SOSFullPeerInfoRef result = NULL;
340 SecKeyRef publicKey = NULL;
341 CFDictionaryRef gestalt = NULL;
343 require(outSigningKey, exit);
344 *outSigningKey = GeneratePermanentFullECKey(256, name, error);
345 require(*outSigningKey, exit);
347 require(outOctagonSigningKey, exit);
348 *outOctagonSigningKey = GeneratePermanentFullECKey(384, name, error);
349 require(*outOctagonSigningKey, exit);
351 require(outOctagonEncryptionKey, exit);
352 *outOctagonEncryptionKey = GeneratePermanentFullECKey(384, name, error);
353 require(*outOctagonEncryptionKey, exit);
355 gestalt = SOSCreatePeerGestaltFromName(name);
356 require(gestalt, exit);
358 result = SOSFullPeerInfoCreate(NULL, gestalt,
361 *outOctagonSigningKey,
362 *outOctagonEncryptionKey,
366 CFReleaseNull(gestalt);
367 CFReleaseNull(publicKey);
372 // MARK: ----- MAC Address -----
375 * Name: GetHardwareAdress
381 * Description: Retrieve the hardare address for a specified network interface
388 #include <sys/socket.h>
389 #include <netinet/in.h>
390 #include <sys/sysctl.h>
392 #include <net/if_dl.h>
393 #include <net/route.h>
397 #include <sys/stat.h>
399 static int getHardwareAddress(const char *interfaceName, size_t maxLenAllowed, size_t *outActualLength, char *outHardwareAddress)
402 struct if_msghdr *ifm;
403 struct sockaddr_dl *sdl;
407 int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET, NET_RT_IFLIST, 0 };
410 *outActualLength = 0;
411 // see how much space is needed
412 require_noerr(result = sysctl(mib, 6, NULL, &buffSize, NULL, 0), xit);
414 // allocate the buffer
415 require(buf = malloc(buffSize), xit);
417 // get the interface info
418 require_noerr(result = sysctl(mib, 6, buf, &buffSize, NULL, 0), xit);
420 ifm = (struct if_msghdr *) buf;
421 end = buf + buffSize;
424 if (ifm->ifm_type == RTM_IFINFO) // should always be true
426 sdl = (struct sockaddr_dl *) (ifm + 1);
427 if ( sdl->sdl_nlen == strlen( interfaceName ) && ( bcmp( sdl->sdl_data, interfaceName, sdl->sdl_nlen ) == 0 ) )
429 if ( sdl->sdl_alen > 0 )
433 result = 0; // indicate found the interface
434 hardwareLen = sdl->sdl_alen;
435 if ( hardwareLen > maxLenAllowed )
437 hardwareLen = maxLenAllowed;
438 result = -2; // indicate truncation of the address
440 memcpy( outHardwareAddress, sdl->sdl_data + sdl->sdl_nlen, hardwareLen );
441 *outActualLength = hardwareLen;
447 ifm = (struct if_msghdr *) ((char*)ifm + ifm->ifm_msglen);
448 } while ( (char*)ifm < end );
457 // MARK: ----- cloudTransportTests -----
459 CFStringRef myMacAddress(void)
462 CFStringRef result = NULL;
463 const char *interfaceName = "en0";
464 size_t maxLenAllowed = 1024;
465 size_t outActualLength = 0;
466 char outHardwareAddress[1024];
468 require_noerr(getHardwareAddress(interfaceName, maxLenAllowed, &outActualLength, outHardwareAddress), xit);
469 require(outActualLength==6, xit);
470 unsigned char buf[32]={0,};
472 unsigned char *ps = (unsigned char *)buf;
473 unsigned char *pa = (unsigned char *)outHardwareAddress;
474 for (int ix = 0; ix < 6; ix++, pa++)
475 ps += sprintf((char *)ps, "%02x", *pa);
477 result = CFStringCreateWithCString(kCFAllocatorDefault, (const char *)buf, kCFStringEncodingUTF8);